BZOJ3787 Gty的文艺妹子序列

Gty的文艺妹子序列

给定一个正整数序列a(1<=ai<=n),支持单点修改,对于每次询问,输出al...ar中的逆序对数,强制在线。

分析

由于强制在线,考虑分块。

\(ans(i,j)\)表示在第\(i\)块取一个元素并在第\(j\)块取一个元素组成的逆序对个数。 那么每次修改操作会涉及到根号个值发生改变,询问操作时需要对第二维进行区间查询。因此第二维用树状数组维护。

\(sum(i,j)\)表示前\(i\)块元素\(j\)的个数,那么修改操作也只会改变根号个值,询问操作需要对第二维进行区间查询,因此第二维用树状数组维护。

\(num(i)\)表示第\(i\)块内逆序对个数,修改操作暴力重算。

分步讨论

设块的大小为\(S\).

初始化

\(ans\)枚举块对,左边计入树状数组,右边统计逆序对,时间复杂度\(O((\frac{N}{S})^2 \cdot S \log N)=O(\frac{N^2}{S} \cdot \log N)\)

\(sum\)枚举块,用树状数组统计逆序对,复杂度\(O(\frac{N}{S} \cdot N \cdot \log N)=O(\frac{N^2}{S} \cdot \log N)\)

\(num\)直接树状数组,复杂度\(O(\frac{N}{S} \cdot S \cdot \log N)=O(N \log N)\)

总复杂度\(O(\frac{N^2}{S} \cdot \log N)\)

区间查询

  1. L,R在距离小于2的块内,直接树状数组统计,复杂度\(O(S \cdot \log N)\)

  2. L,R在距离大于等于2的块内,中间块用ans计算,两边的用树状数组和sum计算,复杂度\(O(\frac{N}{S} \cdot \log \frac{N}{S}+S \cdot \log N)\)

总复杂度\(O(\frac{N}{S} \cdot \log \frac{N}{S}+S \cdot \log N)\)

单点修改

\(ans\)利用\(sum\)修改,复杂度\(O(\frac{N}{S} \cdot \log N)\)

\(sum\)直接修改,复杂度\(O(\frac{N}{S} \cdot \log N)\)

\(num\)直接修改,复杂度\(O(S \cdot \log N)\)

总复杂度\(O(\frac{N}{S} \cdot \log N+S \cdot \log N)\)

总复杂度

\[O(\frac{N^2}{S} \cdot \log N+M \cdot (\frac{N}{S} \cdot \log N+S \cdot \log N)) \]

由于\(M,N\)同阶

\[=O(\frac{N^2}{S} \cdot \log N + N \cdot S \cdot \log N) \geq O(n^{\frac{3}{2}} \cdot \log N) \]

当两项相等时,取等号,而此时

\[S=O(\sqrt{n}) \]

const int MAXN=5e4+7,MAXB=250;

int n,m,blo;
int bl[MAXN],a[MAXN];
int tree[MAXN];
int ans[MAXB][MAXB],sum[MAXB][MAXN],num[MAXB];

int lowbit(int x)
{
	return x&-x;
}

void change(int p,int v) // tree
{
	while(p<=n)
	{
		tree[p]+=v;
		p+=lowbit(p);
	}
}

int query(int p)
{
	int res=0;
	while(p)
	{
		res+=tree[p];
		p-=lowbit(p);
	}
	return res;
}

void change2(int id,int p,int v) // ans
{
	while(p<=bl[n])
	{
		ans[id][p]+=v;
		p+=lowbit(p);
	}
}

int query2(int id,int p)
{
	int res=0;
	while(p)
	{
		res+=ans[id][p];
		p-=lowbit(p);
	}
	return res;
}

void change3(int id,int p,int v) // sum
{
	while(p<=n)
	{
		sum[id][p]+=v;
		p+=lowbit(p);
	}
}

int query3(int id,int p)
{
	int res=0;
	while(p)
	{
		res+=sum[id][p];
		p-=lowbit(p);
	}
	return res;
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
	read(n);
	blo=sqrt(n);
	for(int i=1;i<=n;++i)
	{
		read(a[i]);
		bl[i]=(i-1)/blo+1; // belong
	}
	for(int i=1;i<bl[n];++i)
	{
		for(int j=(i-1)*blo+1;j<=i*blo;++j)
			change(a[j],1);
		for(int j=i+1;j<=bl[n];++j) // cal ans(i,j)
		{
			int t=0;
			for(int k=(j-1)*blo+1;k<=min(j*blo,n);++k)
				t+=query(n)-query(a[k]);
			change2(i,j,t);
		}
		for(int j=(i-1)*blo+1;j<=i*blo;++j)
			change(a[j],-1);
	}
	for(int i=1;i<=bl[n];++i) // cal sum(i,)
		for(int j=1;j<=min(i*blo,n);++j)
			change3(i,a[j],1);
	for(int i=1;i<=bl[n];++i) // cal num(i)
	{
		for(int j=(i-1)*blo+1;j<=min(i*blo,n);++j)
		{
			num[i]+=query(n)-query(a[j]);
			change(a[j],1);
		}
		for(int j=(i-1)*blo+1;j<=min(i*blo,n);++j)
			change(a[j],-1);
	}
	read(m);
	int now=0;
	while(m--)
	{
		int opt;
		read(opt);
		if(opt==0)
		{
			int L,R;
			read(L);read(R);
			L^=now,R^=now;
			now=0;
			int l=bl[L],r=bl[R];
			if(r-l<=1) // in no more than 2 blocks
			{
				for(int i=L;i<=R;++i)
				{
					now+=query(n)-query(a[i]);
					change(a[i],1);
				}
				for(int i=L;i<=R;++i)
					change(a[i],-1);
			}
			else
			{
				for(int i=l+1;i<r;++i) // middle
				{
					now+=num[i];
					now+=query2(i,r-1)-query2(i,i);
				}
				for(int i=L;i<=l*blo;++i) // left
				{
					now+=query(n)-query(a[i]);
					now+=query3(r-1,a[i]-1)-query3(l,a[i]-1);
					change(a[i],1);
				}
				for(int i=(r-1)*blo+1;i<=R;++i) // right
				{
					now+=query(n)-query(a[i]);
					now+=query3(r-1,n)-query3(l,n)-query3(r-1,a[i])+query3(l,a[i]);
					change(a[i],1);
				}
				for(int i=L;i<=l*blo;++i) 
					change(a[i],-1);
				for(int i=(r-1)*blo+1;i<=R;++i)
					change(a[i],-1);	
			}
			printf("%d\n",now);
		}
		else if(opt==1)
		{
			int p,v;
			read(p);read(v);
			p^=now,v^=now;
			for(int i=bl[p]+1;i<=bl[n];++i) // modify right ans
			{
				int t=query3(i,v-1)-query3(i-1,v-1); // add new
				t-=query3(i,a[p]-1)-query3(i-1,a[p]-1); // del old
				change2(bl[p],i,t);
			}
			for(int i=1;i<bl[p];++i) // modify left ans
			{
				int t=query3(i,n)-query3(i-1,n)-query3(i,v)+query3(i-1,v); // add new
				t-=query3(i,n)-query3(i-1,n)-query3(i,a[p])+query3(i-1,a[p]); // del old
				change2(i,bl[p],t);
			}
			for(int i=bl[p];i<=bl[n];++i) //modify suffix sum
			{
				change3(i,a[p],-1);
				change3(i,v,1);
			}
			a[p]=v;
			num[bl[p]]=0;
			for(int i=(bl[p]-1)*blo+1;i<=min(bl[p]*blo,n);++i) // cal num
			{
				num[bl[p]]+=query(n)-query(a[i]);
				change(a[i],1);
			}
			for(int i=(bl[p]-1)*blo+1;i<=min(bl[p]*blo,n);++i)
				change(a[i],-1);
		}
	}
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}


posted on 2018-08-27 20:38  autoint  阅读(99)  评论(0编辑  收藏  举报

导航