CF620E New Year Tree
题面翻译
- 给出一棵 \(n\) 个节点的树,根节点为 \(1\)。每个节点上有一种颜色 \(c_i\)。\(m\) 次操作。操作有两种:
1 u c:将以 \(u\) 为根的子树上的所有节点的颜色改为 \(c\)。2 u:询问以 \(u\) 为根的子树上的所有节点的颜色数量。
- \(1\le n,m\le 4\times 10^5\),\(1\le c_i,c\le 60\)。
样例 #1
样例输入 #1
7 10
1 1 1 1 1 1 1
1 2
1 3
1 4
3 5
3 6
3 7
1 3 2
2 1
1 4 3
2 1
1 2 5
2 1
1 6 4
2 1
2 2
2 3
样例输出 #1
2
3
4
5
1
2
样例 #2
样例输入 #2
23 30
1 2 2 6 5 3 2 1 1 1 2 4 5 3 4 4 3 3 3 3 3 4 6
1 2
1 3
1 4
2 5
2 6
3 7
3 8
4 9
4 10
4 11
6 12
6 13
7 14
7 15
7 16
8 17
8 18
10 19
10 20
10 21
11 22
11 23
2 1
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 4
1 12 1
1 13 1
1 14 1
1 15 1
1 16 1
1 17 1
1 18 1
1 19 1
1 20 1
1 21 1
1 22 1
1 23 1
2 1
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 4
样例输出 #2
6
1
3
3
2
1
2
3
5
5
1
2
2
1
1
1
2
3
分析
考虑到 \(c<60\),\(2^{60}\) long long 刚好装得下。那么把每一个 \(c\) 转为一个二进制位 \(c\) 为 \(1\) 的数,表示区间内有此颜色存在。
对于整个树拍成一个 dfn 序,对于查找一个子树就是子树根节点进出时间范围内的所有节点。
区间总数符合结合律,考虑用线段树维护,记得 pushup 操作是异或操作(因为二进制)
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return x*f;
}
struct node{
int v,nxt;
}e[400005<<1];
int tot,tim,h[400005<<1],in[400005],out[400005],pos[400005<<1];
int a[400005],t[400005<<2],tag[400005<<2];
int n,m;
int lowbit(int x){return x&(-x);}
void dfs(int x,int fa){
pos[in[x]=++tim]=x;
for(int i=h[x];i;i=e[i].nxt)if(e[i].v^fa)dfs(e[i].v,x);
out[x]=tim;
}
void pushup(int num){t[num]=t[num<<1]|t[num<<1|1];}
void pushdown(int num,int l,int r){
if(tag[num]){
tag[num<<1]=tag[num<<1|1]=t[num<<1]=t[num<<1|1]=tag[num];
tag[num]=0;
}
}
void add_edge(int u,int v){e[++tot].v=v,e[tot].nxt=h[u],h[u]=tot;}
void build(int l,int r,int num){
if(l==r){
t[num]=1ll<<a[pos[l]];
return;
}
int mid=l+r>>1;
build(l,mid,num<<1),build(mid+1,r,num<<1|1);
pushup(num);
}
void update(int l,int r,int num,int x,int y,int c){
if(x>r||y<l)return;
if(x<=l&&r<=y){
t[num]=tag[num]=1ll<<c;
return;
}
pushdown(num,l,r);
int mid=l+r>>1;
update(l,mid,num<<1,x,y,c),update(mid+1,r,num<<1|1,x,y,c);
pushup(num);
}
int query(int l,int r,int num,int x,int y){
if(x>r||y<l)return 0;
if(x<=l&&r<=y)return t[num];
pushdown(num,l,r);
int mid=l+r>>1;
return query(l,mid,num<<1,x,y)|query(mid+1,r,num<<1|1,x,y);
}
int get(int x,int ans=0){
for(int i=x;i>0;i-=lowbit(i))++ans;
return ans;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1,x,y;i<n;i++){
x=read(),y=read();
add_edge(x,y),add_edge(y,x);
}
dfs(1,0);build(1,n,1);
for(int i=1,opt,u,c;i<=m;i++){
opt=read();
if(opt==1){
u=read(),c=read();
update(1,n,1,in[u],out[u],c);
}else{
u=read();
printf("%lld\n",get(query(1,n,1,in[u],out[u])));
}
}
return 0;
}

浙公网安备 33010602011771号