题目链接:CF620E
题意: 给你一颗n个节点的树,每个节点被染上了颜色,然后就是m次查询。 查询的方式有两种 1,将以z为根的子树的结点全部更新为颜色X 2,问以z为根的子树的结点的不同颜色数量。默认根为1
Input
第一行输入n,m(4*10^5) 第二行 输入每个节点的颜色(n个) 颜色X<=60 接下来n-1行就是两个点相连 最后m行查询 其中 1 z X 代表操作1, 2 x 代表操作2
Output
输出每次询问的颜色数量
思路:
首先肯定要把树型结构转换为线性结构,所以先用DFS序跑一遍树,将树型结构转换为线性结构,因为树已经变为线性结构所以可以用线段树维护区间,接下来只要解决统计颜色的问题了,这里可以用到二进制的思想,题目说了颜色种数不超过60,所以可以用一个long long的数,每个二进制位代表一个颜色,例如颜色1就是(1<<1)=2,颜色2就是(1<<2)=4,那么如何将两个节点的颜色统计到一个数里面呢,可以知道不同的颜色种数等于两个节点相同的颜色种数+两个节点不同颜色的颜色种数,用到位运算就是(a&b)+(a^b).
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ULL unsigned long long
#define LL long long
#define Max 1000005
#define mem(a,b) memset(a,b,sizeof(a));
#define pb push_back
#define mp make_pair
#define input ios::sync_with_stdio(false);cin.tie(0);
#define debug printf("debug!!!\n");
const LL mod=1e9+7;
const ULL base=131;
const LL LL_MAX=9223372036854775807;
using namespace std;
int in[4*Max],out[4*Max],num[4*Max],tim;
struct node{
int to,next;
}edge[4*Max];
int head[4*Max],tot;
int c[Max*4];
LL tree[Max*4],lazy[Max*4];
int n,m;
void init(){
tot=0;
mem(head,-1);
}
void addedge(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int fa){
in[u]=++tim;
num[tim]=u;
for(int t=head[u];t!=-1;t=edge[t].next){
int to=edge[t].to;
if(to!=fa)
dfs(to,u);
}
out[u]=tim;
}
void build(int root,int l,int r){
if(l==r){
tree[root]=(LL)1<<c[num[l]];
return ;
}
int mid=(l+r)/2;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
tree[root]=(LL)(tree[2*root]&tree[2*root+1])+(LL)(tree[2*root]^tree[2*root+1]);
}
inline void pushdown(int root){
if(lazy[root]!=0){
tree[2*root]=lazy[root];
tree[2*root+1]=lazy[root];
lazy[2*root]=lazy[root];
lazy[2*root+1]=lazy[root];
lazy[root]=0;
}
}
void update(int root,int l,int r,int L,int R,int val){
if(l>=L && r<=R){
tree[root]=(LL)1<<val;
lazy[root]=(LL)1<<val;
return ;
}
pushdown(root);
int mid=(l+r)/2;
if(L<=mid)
update(2*root,l,mid,L,R,val);
if(R>mid)
update(2*root+1,mid+1,r,L,R,val);
tree[root]=(LL)(tree[2*root]&tree[2*root+1])+(LL)(tree[2*root]^tree[2*root+1]);
}
LL query(int root,int l,int r,int L,int R){
if(l>=L && r<=R)
return tree[root];
pushdown(root);
int mid=(l+r)/2;
LL ans1=0,ans2=0;
if(L<=mid){
ans1=query(2*root,l,mid,L,R);
}
if(R>mid){
ans2=query(2*root+1,mid+1,r,L,R);
}
return (LL)(ans1&ans2)+(LL)(ans1^ans2);
}
int main()
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(1,0);
build(1,1,n);
while(m--){
int opt;
scanf("%d",&opt);
if(opt==1){
int root,c;
scanf("%d%d",&root,&c);
update(1,1,n,in[root],out[root],c);
}else{
int root;
scanf("%d",&root);
LL ans=query(1,1,n,in[root],out[root]);
int cot=0;
while(ans){
cot++;
ans&=ans-1;
}
printf("%d\n",cot);
}
}
return 0;
}