[国家集训队]数颜色 / 维护队列

IV.III.[国家集训队]数颜色 / 维护队列

虽然这里这题的写法是CDQ但是我还是要大声喊出:树套树yyds!

首先,众所周知地,我们可以对于每个位置记录其颜色上一次出现的地方,记作 \(las_i\),则我们需要知道的就是 \([l,r]\)\(las_i<l\) 的总数。

众所周知地,这是二维数点问题。现在有了修改操作,需要保证时间顺序,因此变成了大家都喜欢的三维数点问题。

具体操作很简单:因为观察到一次修改最多改变 \(3\) 个位置的 \(las\) 值,放到二维数点的平面上就是 \(6\) 次修改,于是预处理这六次修改的样式,然后CDQ分治时计算左侧的修改对右侧询问的影响就行了。可以采用树状数组简单处理。

但是CDQ分治也有其优点,就是空间复杂度是 \(O(n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[150010],lim,las[150010],res[150010],t[150010];
vector<int>v;
struct node{
	int tp,a,b;
	node(){}
	node(int T,int A,int B){tp=T,a=A,b=B;}
	friend bool operator<(const node&x,const node&y){return x.a==y.a?!x.tp>!y.tp:x.a<y.a;}
}q[150010];
char str[10];
set<int>s[300010];
void ADD(int x,int y){while(x<=n)t[x]+=y,x+=x&-x;}
int SUM(int x){int ret=0;while(x)ret+=t[x],x-=x&-x;return ret;}
vector<node>u,w[150010]; 
void CDQ(int l,int r){
	if(l==r)return;
	int mid=(l+r)>>1;
	for(int i=l;i<=mid;i++)if(!q[i].tp)for(auto j:w[i])u.push_back(j);
	for(int i=mid+1;i<=r;i++)if(q[i].tp)for(auto j:w[i])u.push_back(j);
	sort(u.begin(),u.end());
	for(auto i:u){
		if(!i.tp){
			if(i.b>0)ADD(i.b,1);
			else ADD(-i.b,-1);
		}else{
			if(i.tp>0)res[i.tp]+=SUM(i.b);
			else res[-i.tp]-=SUM(i.b);
		}
	}
	u.clear();
	for(auto i:u)if(!i.tp){
		if(i.b>0)ADD(i.b,-1);
		else ADD(-i.b,1);
	}
	CDQ(l,mid),CDQ(mid+1,r);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),v.push_back(a[i]);
	for(int i=1;i<=m;i++){
		scanf("%s%d%d",str,&q[i].a,&q[i].b),q[i].tp=(str[0]=='Q');
		if(str[0]=='R')v.push_back(q[i].b);
	}
	sort(v.begin(),v.end()),v.resize(lim=unique(v.begin(),v.end())-v.begin());
	for(int i=1;i<=n;i++)s[a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1].insert(i);
	for(int i=1;i<=m;i++)if(!q[i].tp)q[i].b=lower_bound(v.begin(),v.end(),q[i].b)-v.begin()+1;
	for(int i=1;i<=n;i++){
		auto tmp=s[a[i]].lower_bound(i);
		if(tmp!=s[a[i]].begin())las[i]=1+*--tmp;
		else las[i]=1;
	}
	for(int i=1;i<=m;i++){
		if(!q[i].tp)continue;
		u.emplace_back(-i,q[i].a-1,q[i].a),u.emplace_back(i,q[i].b,q[i].a);
		w[i].emplace_back(-i,q[i].a-1,q[i].a),w[i].emplace_back(i,q[i].b,q[i].a);
	}
	sort(u.begin(),u.end());
	for(int i=0,j=1;i<u.size();i++){
		while(j<=u[i].a)ADD(las[j++],1);
		if(u[i].tp>0)res[u[i].tp]+=SUM(u[i].b);else res[-u[i].tp]-=SUM(u[i].b);
	}
	u.clear(),memset(t,0,sizeof(t));
	for(int i=1;i<=m;i++){
		if(q[i].tp)continue;
		int P=q[i].a,C=q[i].b;
		if(C==a[P])continue;
		w[i].emplace_back(0,P,-las[P]);
		s[a[P]].erase(P);
		auto tmp=s[a[P]].lower_bound(P);
		if(tmp!=s[a[P]].end())w[i].emplace_back(0,*tmp,-las[*tmp]),w[i].emplace_back(0,*tmp,las[*tmp]=las[P]);
		
		tmp=s[C].lower_bound(P);
		if(tmp!=s[C].end()){
			w[i].emplace_back(0,P,las[P]=las[*tmp]);
			w[i].emplace_back(0,*tmp,-las[*tmp]);
			w[i].emplace_back(0,*tmp,las[*tmp]=P+1);
		}else if(tmp!=s[C].begin())w[i].emplace_back(0,P,las[P]=1+*--tmp);
		else w[i].emplace_back(0,P,las[P]=1);
		a[P]=C;
		s[C].insert(P);
	}
	CDQ(1,m);
	for(int i=1;i<=m;i++)if(q[i].tp)printf("%d\n",res[i]);
	return 0;
} 

原文地址:https://www.cnblogs.com/Troverld/p/14620786.html