6691. 2020.06.05省选模拟六道剑「一念无量劫」

Posted gmh77

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6691. 2020.06.05省选模拟六道剑「一念无量劫」相关的知识,希望对你有一定的参考价值。

题目描述

妖梦在练习剑术
有 n 个木桩排成一排,从左到右高度分别为 h 1 ,h 2 ,h 3 ,...,h n ,这些高度两两不同
妖梦每次可以选择两个相邻的木桩交换,这样的交换可以进行任意多次
妖梦也可以使用符卡:选择两个木桩交换,但最多只能使用一次。
妖梦想要知道将木桩排成从左到右递增的顺序,她最少需要进行多少次交换。

技术图片

题解

log^3能过60000

如果i要作为左端点的话必须不能有j满足j<i且a[j]>a[i],右端点类似

那么可以找出可能的单调左右端点,原来的每个点的影响范围都可以在上面对应两段区间,建成坐标系就是一个矩形

扫描线即可

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define file
using namespace std;

struct type{int x1,x2,y,s;} d[600001];
int a[300001],tr[1200001][2],Tr[1200001],b[300001],c[300001],n,i,j,k,l,r,mid,t1,t2,tot,find1,find2,X1,X2,Y1,Y2;
bool bz[300001];
ll ans,Ans;

void down(int t,int len)
{
	if (Tr[t])
	{
		if (len>1) Tr[t*2]+=Tr[t],Tr[t*2+1]+=Tr[t];
		tr[t][0]+=Tr[t]*len,tr[t][1]+=Tr[t];
		Tr[t]=0;
	}
}
void up(int t,int len)
{
	tr[t][0]=tr[t*2][0]+Tr[t*2]*((len+1)/2)+tr[t*2+1][0]+Tr[t*2+1]*(len/2);
	tr[t][1]=max(tr[t*2][1]+Tr[t*2],tr[t*2+1][1]+Tr[t*2+1]);
}
void change(int t,int l,int r,int x,int y,int s)
{
	int mid=(l+r)/2;
	down(t,r-l+1);
	if (x<=l && r<=y) {Tr[t]+=s;down(t,r-l+1);return;}
	
	if (x<=mid) change(t*2,l,mid,x,y,s);
	if (mid<y) change(t*2+1,mid+1,r,x,y,s);
	up(t,r-l+1);
}
void find(int t,int l,int r,int x,int y)
{
	int mid=(l+r)/2;
	down(t,r-l+1);
	if (x<=l && r<=y) {find1+=tr[t][0],find2=min(find2,tr[t][1]);return;}
	
	if (x<=mid) find(t*2,l,mid,x,y);
	if (mid<y) find(t*2+1,mid+1,r,x,y);
}

void add(int X1,int X2,int Y1,int Y2) {d[++tot]={X1,X2,Y1,1};d[++tot]={X1,X2,Y2+1,-1};}
bool cmp(type a,type b) {return a.y<b.y;}

int main()
{
	freopen("sword.in","r",stdin);
	#ifdef file
	freopen("sword.out","w",stdout);
	#endif
	
	scanf("%d",&n);
	fo(i,1,n) scanf("%d",&a[i]);
	fd(i,n,1) find1=find2=0,find(1,1,n,1,a[i]),Ans+=find1,change(1,1,n,a[i],a[i],1);
	fd(i,n,1){while (t1 && a[i]>a[b[t1]]) --t1;b[++t1]=i;}
	fo(i,1,n) {while (t2 && a[i]<a[c[t2]]) --t2;c[++t2]=i;}
	fo(i,1,t1) bz[b[i]]=1;
	fo(i,1,t2) bz[c[i]]=1;
	
	fo(i,1,n)
	if (!bz[i])
	{
		l=1;r=t1;
		while (l<r)
		{
			mid=(l+r)/2;
			if (b[mid]>i) l=mid+1; else r=mid;
		}
		X1=l;
		l=1;r=t1;
		while (l<r)
		{
			mid=(l+r)/2;
			if (a[b[mid]]>a[i]) l=mid+1; else r=mid;
		}
		X2=l-(a[b[l]]<a[i]);
		l=1;r=t2;
		while (l<r)
		{
			mid=(l+r)/2;
			if (c[mid]<i) l=mid+1; else r=mid;
		}
		Y1=l;
		l=1;r=t2;
		while (l<r)
		{
			mid=(l+r)/2;
			if (a[c[mid]]<a[i]) l=mid+1; else r=mid;
		}
		Y2=l-(a[c[l]]>a[i]);
		
		add(X1,X2,Y1,Y2);
	}
	if (tot>0)
	{
		memset(tr,0,sizeof(tr));
		memset(Tr,0,sizeof(Tr));
		sort(d+1,d+tot+1,cmp);
		
		fo(i,1,tot)
		{
			change(1,1,n,d[i].x1,d[i].x2,d[i].s);
			if (i==tot || d[i].y!=d[i+1].y) down(1,n),ans=max(ans,tr[1][1]);
		}
	}
	
	printf("%lld
",Ans-ans*2);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}




以上是关于6691. 2020.06.05省选模拟六道剑「一念无量劫」的主要内容,如果未能解决你的问题,请参考以下文章

6692. 2020.06.05省选模拟灵符「无寿之梦」

6692. 2020.06.05省选模拟灵符「无寿之梦」

JZOJ 6693. 2020.06.05省选模拟紫色彼岸樱推迟绽放 (自然数幂拆上升幂+组合意义矩阵乘法+NTT)

JZOJ 6693. 2020.06.05省选模拟紫色彼岸樱推迟绽放 (自然数幂拆上升幂+组合意义矩阵乘法+NTT)

四校省选模拟一

四校省选模拟一