#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;} template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;} const int N=4e5+10,M=0,Z=1e9+7,ms63=0x3f3f3f3f; int n,m,x,y; int col[N]; int first[N], id; int w[N << 1], nxt[N << 1]; bool vis[N]; int in[N], out[N]; int p[N]; int tim; LL b[64]; LL C; struct A { int l,r; LL flag; LL c; }a[1<<20]; void ins(int x,int y) { ++id; w[id]=y; nxt[id]=first[x]; first[x]=id; } void dfs(int x) { vis[x]=1; in[x]=++tim; p[tim]=col[x]; for(int z=first[x];z;z=nxt[z]) { int y=w[z]; if(vis[y])continue; dfs(y); } out[x]=tim; } void pushdown(int o) { if(a[o].flag) { a[ls].flag=a[rs].flag=a[o].flag; a[ls].c |= a[o].flag; a[rs].c |= a[o].flag; a[o].flag=0; } } void pushup(int o) { a[o].c=a[ls].c|a[rs].c; } void build(int o,int l,int r) { a[o].l = l; a[o].r = r; a[o].flag = 0; if(l==r) { a[o].c|=b[ p[l] ]; return; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); pushup(o); return; } void change(int o,int l,int r,LL v) { if(a[o].l==l&&a[o].r==r) { a[o].flag = a[o].c = v; return; } pushdown(o); int mid=(a[o].l+a[o].r)>>1; if(r<=mid)change(ls,l,r,v); else if(l>mid)change(rs,l,r,v); else { change(ls,l,mid,v); change(rs,mid+1,r,v); } pushup(o); } void update(int o,int l,int r) { if(a[o].flag) { C |= a[o].flag; return; } if(a[o].l==l&&a[o].r==r) { C |= a[o].c; return; } int mid=(a[o].l+a[o].r)>>1; if(r<=mid)update(ls,l,r); else if(l>mid)update(rs,l,r); else { update(ls,l,mid); update(rs,mid+1,r); } pushup(o); } int main() { for (int i = 0; i <= 60; ++i)b[i] = 1ll << i; while(~scanf("%d%d",&n,&m)) { memset(first,0,n+2<<2);id=1; for(int i=1;i<=n;++i)scanf("%d",&col[i]); for(int i=1;i<n;++i) { scanf("%d%d",&x,&y); ins(x,y); ins(y,x); } MS(vis,0); tim=0; dfs(1); build(1,1,n); for(int i=1;i<=m;++i) { int o; int p,v; scanf("%d",&o); if(o==1) { scanf("%d%d",&p,&v); change(1,in[p],out[p],b[v]); } else { scanf("%d",&p); C = 0; update(1,in[p],out[p]); printf("%d\n", __builtin_popcountll(C)); } } } return 0; } /* 【题意】 给你一棵树,有n(4e5)个节点,每个节点有一个颜色,颜色范围在[1,60] 我们有两种操作。 操作1:把节点p的子树都改为颜色v 操作2:查询以p为根的子树有多少种不同的颜色。 【类型】 线段树 dfs序 【分析】 我们先得到in和out的dfs序, 然后建线段树,每个节点开60个bool数组,表示颜色数 (或者用LL来表示) 然后对于修改操作,使用flag打标记 对于查询操作,做全局或运算,然后用__builtin_popcountll()求1的个数即可 【时间复杂度&&优化】 O(mlogn) */