CodeForces - 849E cdq分治

cdq分治的题 不过要先推出维度的关系

显然想要得出一种数的答案 我们需要知道这种数在区间里面出现的位置  最后的位置减去最前面的位置即可 

但是我们无法很便捷的找到最后和最前的位置  却可以找出所有出现的位置 

设 pre[i] 为i位置的数上一次出现的位置  对于每一个这样的对(i和pre[i]) 他们的贡献是 i-pre[i]

那么一种数对于整个区间的贡献就是 

i<=R pre[i]>=L 的所有贡献和

三个维度分别是 时间,当前位置 i 和pre[i]

对于每一个询问  它的三个维度我们稍微改一下 设置为 时间 R和L  

我们加入 i <= R 的所有修改  通过树状数组(下标为pre[i])维护后缀和 询问 >=L 的所有贡献即可 

另外我们要用set维护 pre[i]的变化  也就是当p位置修改以后  我们要把修改前的 i和pre[i]的关系进行修改  还要把 i的后继和pre[i]的关系进行修改  修改完以后 也要加入一些关系 (手动模拟一下就懂了)

   

#include
using namespace std;
const int N = 2e5+10;
typedef long long ll;
setcol[N];
int n,m,val[N],a[N];
struct cd{
	int op,p,pr,val,id;
}q[N*10],p[N*10];
int pre[N],tot;
ll c[N],ans[N];
void add(int x,ll val){
	while(x){
		c[x]+=val;
		x-=x&-x;
	}
}
ll query(int x){
	ll ret = 0;
	while(x<=n){
		ret+=c[x];
		x+=x&-x;
	}
	return ret;
}
void clear(int x){
	while(x){
		c[x]=0;
		x-=x&-x;
	}
}
bool cmp(cd a,cd b){
	return a.p>1;
	cdq(L,M);cdq(M+1,R);
	int j = L,c = L;
	for(int i = M+1; i <= R; i++){
		while(j<=M&&q[j].p<=q[i].p){
			if(q[j].op==1) add(q[j].pr,q[j].val);
			p[c++]=q[j++];
		} 
		if(q[i].op==2) ans[q[i].id]+=query(q[i].pr);
		p[c++]=q[i];
	}
	for(int i = L; i < j; i++) if(q[i].op==1) clear(q[i].pr);
	for(int i = j; i <= M; i++) p[c++]=q[i];
	for(int i = L; i < c; i++) q[i]=p[i];
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++){
		scanf("%d",&a[i]);
		if(col[a[i]].empty()) pre[i]=0; else pre[i]=*--col[a[i]].end();
		col[a[i]].insert(i);
		q[++tot]=(cd){1,i,pre[i],i-pre[i],0};	
	}
	for(int i = 1; i <= n; i++) col[i].insert(0);
	int qt = 0;
	for(int i = 1; i <= m; i++){
		int op,x,y,nex;
		scanf("%d%d%d",&op,&x,&y);
		if(op==1){
			q[++tot]=(cd){op,x,pre[x],pre[x]-x,0};
			if(++col[a[x]].lower_bound(x)!=col[a[x]].end()){
				nex = *++col[a[x]].lower_bound(x);
				q[++tot]=(cd){op,nex,pre[nex],pre[nex]-nex,0};
				pre[nex]=pre[x];
				q[++tot]=(cd){op,nex,pre[nex],nex-pre[nex],0};
			}
			col[a[x]].erase(x);a[x]=y;
			col[a[x]].insert(x);pre[x]=*--col[a[x]].lower_bound(x);
			q[++tot]=(cd){op,x,pre[x],x-pre[x],0};
			if(++col[a[x]].lower_bound(x)!=col[a[x]].end()){
				nex = *++col[a[x]].lower_bound(x);
				q[++tot]=(cd){op,nex,pre[nex],pre[nex]-nex,0};
				pre[nex]=x;
				q[++tot]=(cd){op,nex,pre[nex],nex-pre[nex],0};
			}
		}else{
			q[++tot]=(cd){op,y,x,0,++qt};
		}
	}
	cdq(1,tot);
	for(int i = 1; i <= qt; i++) printf("%lld\n",ans[i]);
	return 0;
}

 

你可能感兴趣的:(codeforces,CDQ分治)