• 【学习笔记】四毛子算法


    这算法的名字应该是

    [The Method of Four Russians ]


    引入:[LOJ6499] 颜色

    求一坨区间内出现的颜色个数

    (n,Tle 10^5)(Memory Limits =8 Mib)

    比较简单的做法是分块完了 (bitset)

    然后我们发现这个 (bitset) 是没法做的

    每个询问中间的部分与答案的部分复杂度很高

    那么可以考虑用 (st) 表或者线段树优化这个过程

    这题目直接 (ST) 表加上手写 (Bitset) 就冲过去了

    收获:如何手写 (bitset)(st) 表优化分块的思路

    #include<bits/stdc++.h>
    using namespace std;
    #define reg register
    namespace yspm{
    	inline int read(){
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f; 
    	}
    	const int N=1e5+10,P=(N>>5)+10,SZ=(1<<16)+1;
    	int b[N],c,a[N],n,T,p,bl[N],block,ct[SZ];
    	struct BITSET{
    		unsigned int a[P];
    		BITSET operator |(BITSET tp) const{
    			BITSET res;
    			for(reg int i=0;i<=c;++i) res.a[i]=a[i]|tp.a[i];
    			return res;
    		}  
    		inline void clear(){
    			for(reg int i=0;i<=c;++i) a[i]=0;
    			return ;
    		}
    		inline void set(int x){
    			a[x>>5]|=1u<<(x&31);
    			return ;
    		}
    		inline int count(){
    			int res=0;
    			for(reg int i=0;i<=c;++i){
    				res+=ct[a[i]>>16]+ct[a[i]&65535];
    			}return res;
    		}
    	}ans,f[80][9];
    	inline void work(int l,int r){
    		if(bl[l]+1>=bl[r]){
    			for(reg int i=l;i<=r;++i) ans.set(a[i]);
    		}else{
    			for(reg int i=l;bl[i]==bl[l];++i) ans.set(a[i]);
    			for(reg int i=r;bl[i]==bl[r];--i) ans.set(a[i]);
    			int t=log2(bl[r]-bl[l]-1);
    			ans=ans|f[bl[l]+1][t]|f[bl[r]-(1<<t)][t];
    		} return ;
    	}
    	int lans;
    	signed main(){
    		n=read(); T=read(); p=read(); block=sqrt(1.2*log2(n+1)*n);
    		for(reg int i=1;i<=65535;++i){
    			for(reg int T=i;T;T=(T-1)&T) ++ct[i];
    		} 
    		for(reg int i=1;i<=n;++i) bl[i]=i/block+1,b[i]=a[i]=read();
    		sort(b+1,b+n+1); c=unique(b+1,b+n+1)-b-1;
    		for(reg int i=1;i<=n;++i) {
    			a[i]=lower_bound(b+1,b+c+1,a[i])-b;
    			f[bl[i]][0].set(a[i]);
    		}
    		c>>=5;
    		for(reg int j=1;(1<<j)<=bl[n];++j){
    			for(reg int i=1;i+(1<<j)-1<=bl[n];++i){
    				f[i][j]=f[i][j-1]|f[i+(1<<(j-1))][j-1];
    			}
    		}
    		bool fl=0;
    		while(T--){
    			ans.clear();
    			int k=read(); 
    			while(k--){
    				int l=read(),r=read();
    				if(p&&fl){
    					l=(l^lans)%n+1,r=(r^lans)%n+1;
    				} if(r<l) swap(l,r);
    				work(l,r);
    			}fl=1;
    			printf("%d
    ",lans=ans.count()); 
    		}
    		return 0;
    	}
    }
    signed main(){
    	return yspm::main();
    }
    

    不过这代码里面块的大小是嫖的……

    具体怎么算留坑了

    然后是下一个题目

    https://ac.nowcoder.com/acm/contest/8282/F

    答案容斥完了就是所有颜色剪掉 (dfn) 序不在那个区间里面的情况

    所以四毛子上去即可

    但是卡空间,那么把询问分成 (10) 组再做就行了

    [sto skyh orz ]

    代码还没写

  • 相关阅读:
    2020牛客暑期多校训练营(第二场)G-Greater and Greater bitset
    2020牛客暑期多校训练营(第二场)H Happy Triangle 线段树
    平衡树——splay
    动态规划之状态压缩
    动态规划入门理解
    快速幂入门
    最小生成树初步
    线性筛素数
    最短路径—迪杰斯特拉算法入门
    并查集初步
  • 原文地址:https://www.cnblogs.com/yspm/p/13939970.html
Copyright © 2020-2023  润新知