把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4887 【模板】莫队二次离线(第十四分块(前体))

题面传送门
考虑一般的莫队。复杂度\(O(n\sqrt nC_{14}^{7})\)
这里面转移的复杂度略微有点大。
考虑\([l,r]\)转移到\([l,r+1]\)的贡献。即\(a_{r+1}\)对于\([l,r]\)的贡献。
这个东西可以差分,变成\([1,r]-[1,l-1]\),然后就可以统一计算了。
剩下四种情况同上,注意\(k=0\)的情况。
这就是大名鼎鼎的莫队二次离线,可以将\(O(n\sqrt nk)\)变成\(O(nk+n\sqrt n)\)
代码实现:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define R register
#define CI const int &
using namespace std;
int n,m,k,x,y,z,a[100039],ks,q[100039],f[32039],tots;
int w[100039],head;
long long ans[100039],tot[100039];
struct ques{int l,r,id;}s[100039];
struct yyy{int x,y,id,flag;};
vector<yyy> g[100039];
inline bool cmp(ques x,ques y){return (x.l/ks==y.l/ks)?(((x.l/ks)&1)?x.r>y.r:x.r<y.r):(x.l<y.l);}
inline void make(CI x=0,CI y=0,CI z=0){
	if(x==14){if(y==k)w[++head]=z;return;}
	if(y<k) make(x+1,y+1,z^(1<<x));
	make(x+1,y,z);
}
inline void get(R int x){
	R int i;
	for(i=1;i<=head;i++) f[x^w[i]]++;
}
inline void read(int &x){
	char s=getchar();x=0;
	while(s<'0'||s>'9') s=getchar();
	while(s>='0'&&s<='9') x=x*10+s-48,s=getchar();
}
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	R int i,j,h,lon,l=1,r=0;R ques tmps;R yyy tmp;
	read(n);read(m);read(k);ks=sqrt(n);make();
	if(k>14){for(i=1;i<=m;i++) printf("0\n");return 0;}
	for(i=1;i<=n;i++)read(a[i]);
	for(i=1;i<=n;i++) q[i]=f[a[i]],get(a[i]);
	for(i=1;i<=m;i++) read(x),read(y),s[i]=(ques){x,y,i};
	sort(s+1,s+m+1,cmp);
	for(i=1;i<=m;i++){
		tmps=s[i];
		if(r<tmps.r){
			g[l-1].push_back((yyy){r+1,tmps.r,i,-1});
			while(r<tmps.r) ans[i]+=q[++r];
		} 
		if(r>tmps.r){
			g[l-1].push_back((yyy){tmps.r+1,r,i,1});
			while(r>tmps.r) ans[i]-=q[r--];
		}
		if(l>tmps.l){
			g[r].push_back((yyy){tmps.l,l-1,i,1});
			while(l>tmps.l) ans[i]-=q[--l];
		}
		if(l<tmps.l){
			g[r].push_back((yyy){l,tmps.l-1,i,-1});
			while(l<tmps.l) ans[i]+=q[l++];
		}
	}
	for(memset(f,0,sizeof(f)),i=1;i<=n;i++){
		get(a[i]);lon=g[i].size();
		for(j=0;j<lon;j++){
			tmp=g[i][j];
			for(h=tmp.x;h<=tmp.y;h++){
				if(h<=i&&!k)ans[tmp.id]+=tmp.flag*(f[a[h]]-1);
				else ans[tmp.id]+=tmp.flag*f[a[h]];
			} 
		}
	}
	for(i=1;i<=m;i++) ans[i]+=ans[i-1],tot[s[i].id]=ans[i];
	for(i=1;i<=m;i++) printf("%lld\n",tot[i]);
}
posted @ 2021-02-02 13:49  275307894a  阅读(72)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end