zoukankan      html  css  js  c++  java
  • BZOJ2821 作诗(Poetize) 主席树 bitset

    原文链接https://www.lydsy.com/JudgeOnline/problem.php?id=2821

    题目传送门 - BZOJ2821

    题意

      $n$ 个数,$m$ 组询问,每次问 $[l,r]$ 中有多少个数出现正偶数次。

      $1leq n,m,a_ileq 10^5$

    题解

      这题的标算是一个分块。但是我不想写分块怎么办?

      bitset 大法好!

      bitset 大法好!

      bitset 大法好!

      发现我们可以每隔 $sqrt n$ 保存一下前缀序列中每一个数字的出现情况。

      然后询问的时候相当于找到长度 $L-1$ 的前缀序列的数的出现情况和长度 $R$ 的前缀序列的数的出现情况,异或起来,数 0 的个数即可。这个显然可以通过预处理的东西暴力调整,然后手写 bitset 再加一个预处理可以使统计 0 的个数的复杂度也变成 $O(nm/32)$ 。所以总复杂度 $O(nm/32)$ 。这里注意一下调整 $L-1$ 和 $R$ 的 bitset 不能是同一个!。

      然后发现样例萎掉了。

      发现一个数没有出现过不能算进去。

      那怎么办呢?

      补集转化一下:答案变成 “区间不同数值的种数 - 统计异或得到的 bitset 的 1 的个数” 。

      显然“区间不同数值的种数”是可以通过转化成二维数点问题的,直接拖主席树板子。

      然后就 AC 啦。

      时间复杂度 $O(nlog n+nsqrt n+n^2/32)$ (由于 $n,m,c$ 同阶,所以这里都看作 $n$ )。

    代码

    #include <bits/stdc++.h>
    #define y1 __zzd001
    using namespace std;
    typedef unsigned uint;
    const int N=100405;
    int cnt1[65536];
    void init(){
    	for (int i=0;i<65536;i++)
    		cnt1[i]=cnt1[i>>1]+(i&1);
    }
    struct BitSet{
    	uint v[3200];
    	void clear(){
    		memset(v,0,sizeof v);
    	}
    	uint XOR(int x){v[x>>5]^=1<<(x&31);}
    };
    int calc(uint v){
    	return cnt1[v>>16]+cnt1[v&65535];
    }
    struct Ptree{
    	static const int S=N*40;
    	int n;
    	int root[N],sum[S],ls[S],rs[S],tot;
    	void build(int &rt,int L,int R){
    	    sum[rt=++tot]=0;
    	    if (L==R)
    	        return;
    	    int mid=(L+R)>>1;
    	    build(ls[rt],L,mid);
    	    build(rs[rt],mid+1,R);
    	}
    	void update(int prt,int &rt,int L,int R,int x){
    	    if (!rt||rt==prt)
    	        sum[rt=++tot]=sum[prt];
    	    sum[rt]++;
    	    if (L==R)
    	        return;
    	    if (!ls[rt])
    	        ls[rt]=ls[prt];
    	    if (!rs[rt])
    	        rs[rt]=rs[prt];
    	    int mid=(L+R)>>1;
    	    if (x<=mid)
    	        update(ls[prt],ls[rt],L,mid,x);
    	    else
    	        update(rs[prt],rs[rt],mid+1,R,x);
    	}
    	int query(int rt,int L,int R,int xL,int xR){
    	    if (!rt||R<xL||L>xR)
    	        return 0;
    	    if (xL<=L&&R<=xR)
    	        return sum[rt];
    	    int mid=(L+R)>>1;
    	    return query(ls[rt],L,mid,xL,xR)+query(rs[rt],mid+1,R,xL,xR);
    	}
    	int Query(int x1,int x2,int y1,int y2){
    		if (x1>x2||y1>y2)
    			return 0;
    	    return query(root[x2],0,n,y1,y2)-query(root[x1-1],0,n,y1,y2);
    	}
    	void init(int _n){
    		tot=0;
    		n=_n;
    		build(root[0],0,n);
    	}
    	void insert(int x,int y){
    		update(root[x-1],root[x],0,n,y);
    	}
    }pt;
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return x;
    }
    int n,m,a[N],Pre[N],c;
    BitSet v1[330],v2[330];
    int main(){
    	init();
    	n=read(),c=read(),m=read();
    	pt.init(n);
    	memset(Pre,0,sizeof Pre);
    	for (int i=1;i<=n;i++){
    		a[i]=read();
    		pt.insert(i,Pre[a[i]]);
    		Pre[a[i]]=i;
    	}
    	v1[0].clear(),v2[0]=v1[0];
    	for (int i=1;i*320<=n;i++){
    		v1[i]=v1[i-1];
    		for (int j=(i-1)*320+1;j<=i*320;j++)
    			v1[i].XOR(a[j]);
    		v2[i]=v1[i];
    	}
    	int ans=0;
    	while (m--){
    		int L=(read()+ans)%n+1,R=(read()+ans)%n+1;
    		if (L>R)
    			swap(L,R);
    		int all=pt.Query(L,R,0,L-1);
    		L--;
    		int l=L/320,r=R/320;
    		BitSet &sl=v1[l],&sr=v2[r];
    		l*=320,r*=320;
    		while (l<L)
    			sl.XOR(a[++l]);
    		while (r<R)
    			sr.XOR(a[++r]);
    		int tot=0;
    		for (int i=0;i<3200;i++)
    			tot+=calc(sl.v[i]^sr.v[i]);
    		printf("%d
    ",ans=all-tot);
    		int ls=L/320*320,rs=R/320*320;
    		while (l>ls)
    			sl.XOR(a[l--]);
    		while (r>rs)
    			sr.XOR(a[r--]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    RequestMappin
    数组换位子
    mysql 数据表中查找重复记录(条数)
    post测试
    maven
    常用String练习
    删除重复数据
    推荐几个不错的jQuery图表插件,让你的报表更清晰动感
    纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等),NB么?
    在中国,我们的知识产权真的陨落了吗?
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ2821.html
Copyright © 2011-2022 走看看