【学习笔记】四毛子算法

这算法的名字应该是

[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 ]

代码还没写

原文地址:https://www.cnblogs.com/yspm/p/13939970.html