这个题有一个技巧:把颜色压到一个long long 上。
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; typedef long long LL; LL lft[62],c[400100]; vector<int> e[400100]; int n,m; int pp[400100],lp[400100],rp[400100],len; void dfs(int u,int fa) { pp[++len]=u;lp[u]=len; for(auto& v:e[u]) if(v!=fa) dfs(v,u); rp[u]=len; } #define mid ((l+r)>>1) #define lc (num<<1) #define rc (num<<1|1) LL dat[1600010],setv[1600010]; void build(int l,int r,int num) { setv[num]=-1; if(l==r) {dat[num]=c[pp[l]];return;} build(l,mid,lc);build(mid+1,r,rc); dat[num]=dat[lc]|dat[rc]; } int L,R;LL x; void pd(int l,int r,int num) { if(setv[num]!=-1) { dat[lc]=setv[num];dat[rc]=setv[num]; setv[lc]=setv[num];setv[rc]=setv[num]; setv[num]=-1; } } void change(int l,int r,int num) { if(L<=l&&r<=R) {dat[num]=x;setv[num]=x;return;} pd(l,r,num); if(L<=mid) change(l,mid,lc); if(mid<R) change(mid+1,r,rc); dat[num]=dat[lc]|dat[rc]; } LL query(int l,int r,int num) { if(L<=l&&r<=R) return dat[num]; pd(l,r,num); LL ans=0; if(L<=mid) ans|=query(l,mid,lc); if(mid<R) ans|=query(mid+1,r,rc); return ans; } int main() { int i,a,b,v,idx; lft[0]=1; for(i=1;i<=61;i++) lft[i]=lft[i-1]<<1; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%lld",&c[i]),c[i]=lft[c[i]]; for(i=1;i<n;i++) { scanf("%d%d",&a,&b); e[a].push_back(b);e[b].push_back(a); } dfs(1,0); build(1,n,1); while(m--) { scanf("%d",&idx); if(idx==1) { scanf("%d%lld",&v,&x);x=lft[x]; L=lp[v];R=rp[v];change(1,n,1); } else if(idx==2) { scanf("%d",&v);L=lp[v];R=rp[v]; printf("%d ",__builtin_popcountll(query(1,n,1))); } } return 0; }