To_Heart—題解——CF620E
阿新 • • 發佈:2021-09-03
題目
給個連結
題解
題解
這道題目我們首先通過DFN序將樹的子樹轉換為一個區間,則:
- 每次修改整顆子樹顏色的操作變換為將一個區間的所有值修改。。
- 每次查詢整顆子樹顏色種類的操作變為查詢一個區間內不同值的個數。
然後這個東西就可以很自然的想到線段樹。
這時我們發現顏色不會超過60,所以可以狀態壓縮成一個在long long範圍內的數,最後查詢用Lowbit就好了。
程式碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define int ll int n,m; vector<int> v[400005]; int col[400005]; int DFS_col[400005]; int p[400005]; int sz[400005]; int tot=0; void DFS(int x,int fa){ p[x]=++tot; DFS_col[p[x]]=col[x]; sz[x]=1; for (int i=0;i<v[x].size();i++) { int y=v[x][i]; if(y==fa) continue; DFS(y,x); sz[x]+=sz[y]; } } struct zz{ int l,r; ll col,lazy; }; struct Tree{ zz t[2000005]; void Push_Up(int p){ t[p].col = t[p<<1].col | t[p<<1|1].col; } void Push_Down(int p){ if(!t[p].lazy) return ; ll now=t[p].lazy; t[p<<1].col=t[p<<1].lazy=now; t[p<<1|1].col=t[p<<1|1].lazy=now; t[p].lazy=0; } void Build_Tree(int p,int l,int r){ t[p].l=l,t[p].r=r; t[p].lazy=0; if(l==r){ t[p].col=1ll<<DFS_col[r]; return ; } int mid=(l+r)>>1; Build_Tree(p<<1,l,mid); Build_Tree(p<<1|1,mid+1,r); Push_Up(p); } void Change_Tree(int p,int l,int r,int k){ if(l<=t[p].l&&t[p].r<=r){ t[p].col=t[p].lazy=k; return; } int mid=(t[p].l+t[p].r)>>1; Push_Down(p); if(l<=mid) Change_Tree(p<<1,l,r,k); if(mid+1<=r) Change_Tree(p<<1|1,l,r,k); Push_Up(p); } ll Find_Tree(int p,int l,int r){ if(l<=t[p].l&&t[p].r<=r){ return t[p].col; } int mid=(t[p].l+t[p].r)>>1; Push_Down(p); ll now=0; if(l<=mid) now|=Find_Tree(p<<1,l,r); if(mid+1<=r) now|=Find_Tree(p<<1|1,l,r); return now; } }t; ll Find(ll x){ ll tot=0; while(x){ if(x&1) tot++; x>>=1; } return tot; } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++) scanf("%lld",&col[i]); for(int i=1;i<n;i++){ int x,y; scanf("%lld%lld",&x,&y); v[x].push_back(y); v[y].push_back(x); } DFS(1,-1); t.Build_Tree(1,1,n); while(m--){ int op; scanf("%lld",&op); if(op&1){ int x,y; scanf("%lld%lld",&x,&y); t.Change_Tree(1,p[x],p[x]+sz[x]-1,1ll<<y); } else{ int x; scanf("%lld",&x); printf("%lld\n",Find(t.Find_Tree(1,p[x],p[x]+sz[x]-1))); } } return 0; }