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<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
typedef long long ll;
set<int>col[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<b.p;
}
void cdq(int L,int R){
	if(L==R) return;
	int M = L+R>>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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章