http://codeforces.com/contest/620/problem/E
C《60,n<=1e5
题意:给你n个节点的 无向有根树
给你每个节点的初始颜色ci
q次操作
操作1:1 v k 把v节点的所有子节点颜色都换成k
操作2:2 v 查询v节点的所有子节点颜色种类
先dfs跑一遍得到 一个dfs序
把每个节点涂上初始颜色, 每个节点在dfs序中的位置是in[i], 也就是update(in[i],val);
这个颜色只有60种,我们用一个int64变量来表示即可
那么每次操作1 ,我们就update线段树的【 in[i],out[i]】区间为 值 1<<(kind-1);
每次操作2 ,就查询【 in[i],out[i]】的和
维护颜色种类的时候直接用|操作非常方便, 维护的一个值x,其二进制下1的个数代表其管辖区间的颜色种类
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <stack> #include <iostream> using namespace std; __int64 inf=15; double eps=0.000001; const __int64 N=4*100000+5; vector < vector<__int64> > mp(N); __int64 id; __int64 in[N],out[N]; __int64 vis[N]; void dfs1(__int64 x) { in[x]=++id; vis[x]=1; __int64 i; for (i=0;i<mp[x].size();i++) { __int64 v=mp[x][i]; if (vis[v]) continue; dfs1(v); } out[x]=id; } __int64 add[N*4]; __int64 sum[N*4]; void pushDown(__int64 i,__int64 l,__int64 r) { if (add[i]) { __int64 mid=(l+r)>>1; add[i<<1]=add[i]; sum[i<<1]=add[i]; add[i<<1|1]=add[i]; sum[i<<1|1]=add[i]; add[i]=0; } } void update(__int64 i,__int64 l ,__int64 r,__int64 ql,__int64 qr,__int64 val) { if (l>qr||r<ql) return ; if (l>=ql&&r<=qr) { sum[i]=val; add[i]=val; return ; } pushDown(i,l,r); __int64 mid=(l+r)>>1; update(i<<1,l,mid,ql,qr,val); update(i<<1|1,mid+1,r,ql,qr,val); sum[i]=sum[i<<1]|sum[i<<1|1]; } __int64 query(__int64 i,__int64 l,__int64 r,__int64 ql,__int64 qr ) { if (l>qr||r<ql) return 0; if (l>=ql&&r<=qr) return sum[i]; pushDown(i,l,r); __int64 mid=(l+r)>>1; __int64 ret1=query(i<<1,l,mid,ql,qr); __int64 ret2=query(i<<1|1,mid+1,r,ql,qr); return ret1|ret2; } __int64 cc[N]; int main() { __int64 one=1; __int64 x,y,i; int n,q; cin>>n>>q; id=0; for (i=1;i<=n;i++) scanf("%I64d",&cc[i]); for (i=1;i<=n-1;i++) { scanf("%I64d%I64d",&x,&y); mp[x].push_back(y); mp[y].push_back(x); } dfs1(1); for (i=1;i<=n;i++) { __int64 xx=one<<(cc[i]-1); update(1,1,n,in[i],in[i],xx); } __int64 op,vv,kk; for (i=1;i<=q;i++) { scanf("%I64d",&op); if (op==1) { scanf("%I64d%I64d",&vv,&kk); __int64 xx=one<<(kk-1); update(1,1,n,in[vv],out[vv],xx); } else { scanf("%I64d",&vv); __int64 ans=query(1,1,n,in[vv],out[vv]); __int64 cun=0; while(ans) { cun+=ans%2; ans>>=1; } printf("%I64d\n",cun); } } return 0; }