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;
}