bzoj 2821: 作诗(Poetize)【分块】

参考:http://hzwer.com/3663.html
除了麻烦一点也没什么难的,就是要注意细节。
首先\( O(n\sqrt{n}) \)时间下预处理出\( f[i][j] \),表示第\( i \)块和第\( j \)块之间的答案。\( L \)表示这个块的左端点,\( R \)表示这个块的右端点,\( v\)标记计算过程中已经被算到答案里的数字,\( bl \)表示这个节点属于第几个块,\( fr \)表示当前这个值最早出现的位置,\( la \)表示当前这个值最晚出现的位置。
询问的时候,当\( (l,r) \)处于同一个或者相邻两个快里,则直接暴力统计。否则把其完全跨越的块用\( f \) 查询,得到中间大块\( x-y \)的答案,考虑\( l-x \)和\( y-r \)对答案的影响,对于每个数统计它在\( x-y \)出现次数\( t1 \),以及\( l-r \)出现次数\( t2 \),根据\( t1 \),\( t2 \)的奇偶性考虑其对答案的影响。
对于清理数组要用\( for \),否则无法保证复杂度。
时间复杂度:\( O(n\sqrt{n}log_2n) \)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100005,K=1505,inf=1e9;
int n,m,c,kuai,cnt,bl[N],L[N],R[N],tmp[N],f[K][K],fr[N],la[N],las,a[N];
bool v[N];
struct qwe
{
	int p,v;
}b[N];
bool cmp(const qwe &a,const qwe &b)
{
	return (a.v<b.v)||(a.v==b.v&&a.p<b.p);
}
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p<'0'||p>'9')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
int up(int x,int v)
{
	int l=fr[v],r=la[v],re=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(x<b[mid].p)
			r=mid-1;
		else
			l=mid+1,re=mid;
	}
	return re;
}
int down(int x,int v)
{
	int l=fr[v],r=la[v],re=inf;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(x>b[mid].p)
			l=mid+1;
		else
			re=mid,r=mid-1;
	}
	return re;
}
int zhao(int x,int y,int v)
{
	return max(up(y,v)-down(x,v)+1,0);
}
int ques(int x,int y)
{
	int ans=0,t1,t2,a1,bx=bl[x],by=bl[y];
	if(bx==by||bx+1==by)
	{
		for(int i=x;i<=y;i++)
			if(!v[a[i]])
			{
				int t=zhao(x,y,a[i]);
				if(!(t&1))
				{
					v[a[i]]=1;
					ans++;
				}
			}
		for(int i=x;i<=y;i++)
			v[a[i]]=0;
	}
	else
	{
		int l=L[bx+1],r=R[by-1];
		ans=f[bx+1][by-1];
		for(int i=x;i<l;i++)
			if(!v[a[i]])
			{
				t1=zhao(x,y,a[i]),t2=zhao(l,r,a[i]);
				if(!(t1&1))
				{
					if((t2&1)||!t2)
						ans++;
				}
				else if(!(t2&1)&&t2)
					ans--;
				v[a[i]]=1;
			}
		for(int i=r+1;i<=y;i++)
			if(!v[a[i]])
			{
				t1=zhao(x,y,a[i]),t2=zhao(l,r,a[i]);
				if(!(t1&1))
				{
					if((t2&1)||!t2)
						ans++;
				}
				else if(!(t2&1)&&t2)
					ans--;
				v[a[i]]=1;
			}
		for(int i=x;i<l;i++)
			v[a[i]]=0;
		for(int i=r+1;i<=y;i++)
			v[a[i]]=0;
	}
	return ans;
}
int main()
{
	n=read(),c=read(),m=read();//cout<<n<<m<<c;
	for(int i=1;i<=n;i++)
		a[i]=read();
	kuai=sqrt((double)n/log((double)n)*log(2));
	if(n%kuai)
		cnt=n/kuai+1;
	else
		cnt=n/kuai;
	for(int i=1;i<=n;i++)
		bl[i]=(i-1)/kuai+1;
	for(int i=1;i<=cnt;i++)
		L[i]=(i-1)*kuai+1,R[i]=i*kuai;
	R[cnt]=n;
	int tot;
	for(int i=1;i<=cnt;i++)
	{
		for(int j=L[i];j<=n;j++)
			tmp[a[j]]=0;
		tot=0;
		for(int j=L[i];j<=n;j++)
		{
			if(!(tmp[a[j]]&1)&&tmp[a[j]])//注意当a[j]的个数为0的时候就不用减了
				tot--;
			tmp[a[j]]++;
			if(!(tmp[a[j]]&1))
				tot++;
			f[i][bl[j]]=tot;
		}
	}
	for(int i=1;i<=n;i++)
		b[i].p=i,b[i].v=a[i];
	sort(b+1,b+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		if(!fr[b[i].v])
			fr[b[i].v]=i;
		la[b[i].v]=i;
	}
	while(m--)
	{
		int l=read(),r=read(),x=(l+las)%n+1,y=(r+las)%n+1;
		if(x>y)
			swap(x,y);
		las=ques(x,y);
		printf("%d\n",las);
	}
	return 0;
}
posted @ 2018-01-05 21:22  lokiii  阅读(169)  评论(0编辑  收藏  举报