GDSOI 2019 day1 颜色

一个和标算不同的做法
题目中说所有颜色最多只会在询问中出现一次。
注意到一个修改操作中,只有它包含的节点构成的虚树有贡献。
对于一个修改操作,把所有它包含的颜色(设有\(k\)个)拿出来建虚树。
这样子建虚树的节点数是\(O(n)\)的。
在虚树上,所有子树颜色个数\(=k\)的点都会对答案产生贡献。
求出这些点可以扫描线+dfs序+树状数组(HH的项链)
接下来求出这些点后,我们要把它的链并上的所有节点的权值+1。
可以再用一个虚树,但是比较难写且常数大。
可以使用树状数组维护。
把所有点按照dfs序排序,把每个点处+val,相邻点的lca处-val即可。
被卡常的代码:

#include<bits/stdc++.h>
using namespace std;
#define N 2000010
#define int long long
int n,m,h[N],v[N],nxt[N],ec,f[N],tp[N],p[N],sz[N],d[N],id[N],ct,st[N],ts,ss[N],tv,bt[N],nm,val,c[N],vi[N];
void add(int x,int y){
	v[++ec]=y;
	nxt[ec]=h[x];
	h[x]=ec;
}
void at(int x,int y){
	for(;x<=n;x+=x&-x)
		bt[x]+=y;
}
int lc(int x,int y){
	while(tp[x]!=tp[y]){
		if(d[tp[x]]<d[tp[y]])
			y=f[tp[y]];
		else
			x=f[tp[x]];
	}
	if(d[x]<d[y])
		return x;
	return y;
}
int qu(int x){
	int ans=0;
	for(;x;x-=x&-x)
		ans+=bt[x];
	return ans;
}
vector<int>vc[N],vb[N];
int cp(int x,int y){
	return id[x]<id[y];
}
void d1(int x,int fa){
	sz[x]=1;
	f[x]=fa;
	id[x]=++ct;
	for(int i=h[x];i;i=nxt[i])
		if(v[i]!=fa){
			d[v[i]]=d[x]+1;
			d1(v[i],x);
			sz[x]+=sz[v[i]];
			if(sz[p[x]]<sz[v[i]])
				p[x]=v[i];
		}
}
void d2(int x,int fa,int t){
	tp[x]=t;
	if(p[x])
		d2(p[x],x,t);
	for(int i=h[x];i;i=nxt[i])
		if(v[i]!=fa&&v[i]!=p[x])
			d2(v[i],x,v[i]);
}
void ins(int x){
	if(!tp){
		st[++ts]=x;
		ss[++tv]=x;
		return;
	}
	int ll=lc(x,st[ts]);
	if(ll==st[ts]){
		st[++ts]=x;
		ss[++tv]=x;
		return;
	}
	while(ts>1&&id[st[ts-1]]>=id[ll]){
		vb[st[ts-1]].push_back(st[ts]);
		//cerr<<st[ts-1]<<' '<<st[ts]<<'\n';
		ts--;
	}
	if(ll!=st[ts]){
		ss[++tv]=ll;
		vb[ll].push_back(st[ts]);
		//cerr<<ll<<' '<<st[ts]<<'\n';
		st[ts]=ll;
	}
	st[++ts]=x;
	ss[++tv]=x;
}
void bd(vector<int>x){
	sort(x.begin(),x.end(),cp);
	for(int i=0;i<x.size();i++)
		ins(x[i]);
	for(int i=2;i<=ts;i++){
		vb[st[i-1]].push_back(st[i]);
		//cerr<<st[i-1]<<' '<<st[i]<<'\n';
	}
}
struct qp{
	int l,i;
};
struct dst{
	int in[N],la[N],bt[N],sz[N],ct,va[N],st[N],sv[N],tp,tt;
	vector<qp>qv[N];
	void ad(int x,int y){
		for(;x<=ct;x+=x&-x)
			bt[x]+=y;
	}
	int qu(int x){
		int ans=0;
		for(;x;x-=x&-x)
			ans+=bt[x];
		return ans;
	}
	void dd(int x){
		if(vi[x]){
			in[x]=++ct;
			st[ct]=x;
			sz[x]=1;
		}
		else
			in[x]=1e9;
		ss[++tt]=x;
		for(int i=0;i<vb[x].size();i++){
			int y=vb[x][i];
			dd(y);
			sz[x]+=sz[y];
			in[x]=min(in[x],in[y]);
		}
		qv[in[x]+sz[x]-1].push_back((qp){in[x],x});
	}
	void dt(){
		for(int i=1;i<=ct;i++){
			if(la[c[st[i]]])
				ad(la[c[st[i]]],-1);
			ad(i,1);
			la[c[st[i]]]=i;
			for(int j=0;j<qv[i].size();j++){
				qp y=qv[i][j];
				va[y.i]=qu(i)-qu(y.l-1);
			}
		}
		tp=0;
		for(int i=1;i<=tt;i++)
			if(va[ss[i]]==nm)
				sv[++tp]=ss[i];
		sort(sv+1,sv+tp+1,cp);
		for(int i=1;i<=tp;i++){
			at(id[sv[i]],val);
			if(i!=1)
				at(id[lc(sv[i-1],sv[i])],-val);
		}
	}
	void rb(){
		for(int i=0;i<=ct;i++){
			bt[i]=0;
			qv[i].clear();
		}
		for(int i=1;i<=tp;i++)
			sv[i]=0;
		ct=tp=tt=0;
		for(int i=1;i<=tv;i++){
			in[ss[i]]=sz[ss[i]]=la[c[ss[i]]]=va[ss[i]]=vi[ss[i]]=st[i]=0;
			vb[ss[i]].clear();
		}
	}
}vg;
int rd(){
	int x=0;
	char c=getchar();
	while(!isdigit(c))
		c=getchar();
	while(isdigit(c)){
		x=x*10+c-'0';
		c=getchar();
	}
	return x;
}
signed main(){
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<n;i++){
		int x=rd(),y=rd();
		x++;
		y++;
		add(x,y);
		add(y,x);
	}
	d1(1,0);
	d2(1,0,1);
	for(int i=1;i<=n;i++){
		c[i]=rd();
		c[i]++;
		vc[c[i]].push_back(i);
	}
	int la=0;
	for(int i=1;i<=m;i++){
		int op=rd();
		if(op==1){
			int p=rd();
			vector<int>vs;
			nm=p;
			int ct=0;
			for(int j=1;j<=p;j++){
				int x=rd();
				x=(x+la)%n;
				x++;
				for(int k=0;k<vc[x].size();k++){
					ct+=vc[x].size();
					vs.push_back(vc[x][k]);
					vi[vc[x][k]]=1;
				}
			}
			val=rd();
			if(ct){
				if(!vi[1])
					vs.push_back(1);
				bd(vs);
				vg.dd(1);
				vg.dt();
			}
			vg.rb();
			ts=0;
			tv=0;
		}
		else{
			int x;
			x=rd();
			x=(x+la)%n;
			x++;
			printf("%lld\n",la=qu(id[x]+sz[x]-1)-qu(id[x]-1));
		}
	}
}
posted @ 2020-12-09 08:22  celerity1  阅读(93)  评论(0编辑  收藏  举报