一个和标算不同的做法
题目中说所有颜色最多只会在询问中出现一次。
注意到一个修改操作中,只有它包含的节点构成的虚树有贡献。
对于一个修改操作,把所有它包含的颜色(设有(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]<<'
';
ts--;
}
if(ll!=st[ts]){
ss[++tv]=ll;
vb[ll].push_back(st[ts]);
//cerr<<ll<<' '<<st[ts]<<'
';
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]<<'
';
}
}
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
",la=qu(id[x]+sz[x]-1)-qu(id[x]-1));
}
}
}