Description

一棵 n 个点的树, 树根为 1.
一开始每个点上有一个 1…n 的颜色 ci, 不同点颜色可以相同.
现在有 q 次操作, 分为两种类型:
• 1 u l r: 询问子树 u 中有多少种在 l 到 r 之间的颜色至少出现了一次
• 2 u c: 将 u 的颜色修改为 c

要求强制在线
n,q<=100000

Solution

这题先不要转到DFS序列上做

考虑把同一种颜色的点抽出来,在这个点上+1,在DFS序相邻的两个点的LCA上-1,可以开N个set实现

那么就变成了子树求和问题
此时再转到DFS序列上q,区间的区间求和,也就是二维矩形求和,可以树状数组套线段树实现,树状数组每个节点对应一棵线段树,注意动态开点。

修改相当于查询前一个和后一个,set中二分即可

复杂度O((N+Q)log2N)

Code

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <set>
#define N 200005
#define M 36000005
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int dfn[N],dfw[N],sz[N],nt[2*N],dt[2*N],fs[N],n,m,c[N],q,tq,n1,t[M][2],lst[N],nxt[N],rt[N],cl[N],s1[M],c2[N],f[2*N][20],dep[N];
set<int> cr[N];
void dfs(int k,int fa)
{
sz[k]=1;
f[k][0]=fa;
dfn[k]=++dfn[0];
dep[k]=dep[fa]+1;
dfw[dfn[k]]=k;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa) dfs(p,k),sz[k]+=sz[p];
}
}
void link(int x,int y)
{
nt[++m]=fs[x];
dt[fs[x]=m]=y;
}
void up(int k)
{
s1[k]=s1[t[k][0]]+s1[t[k][1]];
}
void ins(int k,int l,int r,int w,int v)
{
if(l==r&&l==w) s1[k]+=v;
else
{
int mid=(l+r)/2;
if(!t[k][0]) t[k][0]=++n1,t[k][1]=++n1;
if(w<=mid) ins(t[k][0],l,mid,w,v);
else ins(t[k][1],mid+1,r,w,v);
up(k);
}
}
int sum(int k,int l,int r,int x,int y)
{
x=max(x,l),y=min(y,r);
if(x>y||k==0||(s1[k]==0&&!t[k][0])) return 0;
if(l==x&&r==y) return s1[k];
else
{
int mid=(l+r)/2;
return sum(t[k][0],l,mid,x,y)+sum(t[k][1],mid+1,r,x,y);
}
}
int lowbit(int k)
{
return k&(-k);
}
void put(int k,int c,int v)
{
if(k)
while(k<=n)
{
if(!rt[k]) rt[k]=++n1;
ins(rt[k],1,n,c,v);
k+=lowbit(k);
}
}
int get(int k,int x,int y)
{
int s=0;
while(k)
{
if(!rt[k]) rt[k]=++n1;
s+=sum(rt[k],1,n,x,y);
k-=lowbit(k);
}
return s;
}
int lca(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
int j=19;
while(dep[y]>dep[x])
{
while(j&&dep[f[y][j]]<dep[x]) j--;
y=f[y][j];
}
j=19;
while(x!=y)
{
while(j&&f[x][j]==f[y][j]) j--;
x=f[x][j],y=f[y][j];
}
return x;
}
int main()
{
freopen("xmastree1.in","r",stdin);
freopen("xmastree1.out","w",stdout);
cin>>n>>q>>tq;
fo(i,1,n) scanf("%d",&c[i]);
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y),link(y,x);
}
dfs(1,0);
fo(j,1,19)
fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
fo(i,1,n) cr[i].insert(n+1),cr[i].insert(0);
fo(i,1,n)
{
cr[c[i]].insert(dfn[i]);
lst[i]=cl[c[dfw[i]]];
nxt[lst[i]]=i;
cl[c[dfw[i]]]=i;
if(lst[i]) put(dfn[lca(dfw[lst[i]],dfw[i])],c[dfw[i]],-1);
put(i,c[dfw[i]],1);
}
int last=0;
fo(i,1,q)
{
int p,x,y,t;
scanf("%d%d",&p,&t);
if(tq) t^=last;
int t1=t;
if(p==1)
{
scanf("%d%d",&x,&y);
if(tq) x^=last,y^=last;
last=get(dfn[t]+sz[t]-1,x,y)-get(dfn[t]-1,x,y);
printf("%d\n",last);
}
else
{
scanf("%d",&x);
if(tq) x^=last;
if(x==c[t]) continue;
cr[c[t]].erase(dfn[t]);
if(lst[dfn[t]]) put(dfn[lca(dfw[lst[dfn[t]]],t)],c[t],1);
put(dfn[t],c[t],-1);
lst[nxt[dfn[t]]]=lst[dfn[t]];
nxt[lst[dfn[t]]]=nxt[dfn[t]];
nxt[0]=lst[0]=0;
if(nxt[dfn[t]])
{
put(dfn[lca(t,dfw[nxt[dfn[t]]])],c[t],1);
if(lst[dfn[t]]) put(dfn[lca(dfw[nxt[dfn[t]]],dfw[lst[dfn[t]]])],c[t],-1);
}
c[t]=x;
cr[x].insert(dfn[t]);
set<int>::iterator it=cr[x].lower_bound(dfn[t]);
--it;
if((*it)==0) lst[dfn[t]]=0;
else
{
lst[dfn[t]]=*it;
put(dfn[lca(dfw[lst[dfn[t]]],t)],x,-1);
nxt[lst[dfn[t]]]=dfn[t];
}
put(dfn[t],x,1);
it=cr[x].upper_bound(dfn[t]);
if((*it)==n+1) nxt[dfn[t]]=0;
else
{
nxt[dfn[t]]=*it;
put(dfn[lca(t,dfw[nxt[dfn[t]]])],x,-1);
if(lst[dfn[t]]) put(dfn[lca(dfw[lst[dfn[t]]],dfw[nxt[dfn[t]]])],x,1);
lst[nxt[dfn[t]]]=dfn[t];
}
}
}
}