[BZOJ2906]「颜色」

为什么C++ (11)-O2如此之快,直接优化1000ms...
强制在线,只能分块了。
本题应当预处理出每个块到后面几个块的每种数的平方与数量的前缀和。
由于空间限制,块长只能开到n的2/3次方,
最重要的一点,开O2!!!
Code:

#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e4+100,M=2e4+100;
int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;}
int pos[N],n,m,Q,c[N],L[40],R[40],size,t;ll lans,cnt[M],tot[40][40][M],num[40][M];//num记录数量,tot记录平方。
void init()
{
	for(int i=1;i<=t;i++)for(int j=1;j<=m;j++)num[i][j]+=num[i-1][j];
	for(int i=1;i<=t;i++)for(int j=i;j<=t;j++)for(int k=1;k<=m;k++)tot[i][j][k]=tot[i][j][k-1]+(num[j][k]-num[i-1][k])*(num[j][k]-num[i-1][k]);
}
void getans(int l,int r,int a,int b)
{
	int pl=pos[l],pr=pos[r];
	lans=tot[pl+1][pr-1][b]-tot[pl+1][pr-1][a-1];
	if(pl==pr)
	{
		for(int i=l;i<=r;i++)if(c[i]>=a&&c[i]<=b)lans+=cnt[c[i]]*2+1,cnt[c[i]]++;
		for(int i=l;i<=r;i++)cnt[c[i]]=0;
	}
	else
	{
		for(int i=l;i<=R[pl];i++)
		{
			if(c[i]<a||c[i]>b)continue;
			if(!cnt[c[i]])cnt[c[i]]=num[pr-1][c[i]]-num[pl][c[i]];
			lans+=cnt[c[i]]*2+1;cnt[c[i]]++;
		}
		for(int i=L[pr];i<=r;i++)
		{
			if(c[i]<a||c[i]>b)continue;
			if(!cnt[c[i]])cnt[c[i]]=num[pr-1][c[i]]-num[pl][c[i]];
			lans+=cnt[c[i]]*2+1;cnt[c[i]]++;
		}
		for(int i=l;i<=R[pl];i++)cnt[c[i]]=0;
		for(int i=L[pr];i<=r;i++)cnt[c[i]]=0;
		return;
	}
}
int main()
{
	n=read();m=read();Q=read();
	size=pow(n,2.0/3.0),t=ceil((double)n/size);
	for(int i=1;i<=t;i++)L[i]=R[i-1]+1,R[i]=min(n,L[i]+size-1);
	for(int i=1;i<=t;i++)for(int j=L[i];j<=R[i];j++)pos[j]=i;
	for(int i=1;i<=n;i++)c[i]=read(),num[pos[i]][c[i]]++;
	init();
	while(Q--)
	{
		int l=read()^lans,r=read()^lans,a=read()^lans,b=read()^lans;
		getans(l,r,a,b);
		printf("%lld\n",lans);
	}
}
posted @ 2021-05-28 16:28  letitdown  阅读(104)  评论(0编辑  收藏  举报