zoukankan      html  css  js  c++  java
  • bzoj 2821: 作诗(Poetize)【分块】

    参考:http://hzwer.com/3663.html
    除了麻烦一点也没什么难的,就是要注意细节。
    首先( O(nsqrt{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(nsqrt{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
    ",las);
    	}
    	return 0;
    }
    
  • 相关阅读:
    不得不爱开源 Wijmo jQuery 插件集(6)【Popup】(附页面展示和源码)
    遗漏的知识点
    初识函数
    ==和is的区别 以及编码和解码
    函数的动态参数 及函数嵌套
    基本数据类型补充、set集合、深浅拷贝
    文件操作
    基本数据类型之“字典”
    建立自己的Servlet
    还原误删数据笔记
  • 原文地址:https://www.cnblogs.com/lokiii/p/8206836.html
Copyright © 2011-2022 走看看