題解 CF620E 【New Year Tree】
阿新 • • 發佈:2020-11-03
有關dfs序的例題,需要有一定的位運算基礎
題面
- 給定一個樹,樹上有顏色,將某一子樹的顏色統一修改,求子樹中顏色的數量
Solution
- 子樹修改,子樹求和,dfs序的知識(類似區間修改區間求和)
- 考慮到顏色的個數問題,利用位運算進行表示。
- 最後答案用二進位制表示,\(\ 1\)表示有該種顏色,\(\ 0\)表示沒有,
- 因此還需考慮答案\(\ 1\)的數量。
- dfs序問題自然用到線段樹進行維護。
具體介紹一下位運算,和一些小錯誤
- 方案總數不是兩個節點維護的方案數的簡單相加,而是“|”(或)
- 答案維護的是顏色的個數,但不是具體數值
- 關於答案\(\ 1\)的個數,可以利用快速冪
- 也可利用\(\ lowbit\)
- 建樹的時候特別記住需要\(\ long \ long\)的地方
更加詳細的內容
Code
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int manx=1e6+10; const int mamx = 1e7 + 11; const int B = 1e6 + 11; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } struct nodee{ int l,r; ll sum; ll add; }e[manx<<2+2]; int clr[manx<<1]; struct node{ int u; int v; int nxt; int w; }ee[manx]; int head[manx],js,l[manx],r[manx],cnt,n,m,dfn[manx]; int add(int u,int v){ ee[++cnt].u = u; ee[cnt].nxt = head[u]; ee[cnt].v = v; //e[cnt].w = w; head[u] = cnt; } inline void init(){ cnt=js=0; clr(head,-1); } //大法師 void dfs(int u, int pre){ js++; l[u] = js; dfn[js] = u; for(int i = head[u];~i;i = ee[i].nxt){ int v = ee[i].v; if( v == pre ) continue; dfs(v,u); } r[u] = js; //我們可以只記錄他的入段,尾端那個不必重複 return ; } //線段樹 void uploat(int s){//上傳 e[s].sum = 0; if(e[s<<1].l) e[s].sum |=e[s<<1].sum ; if(e[s<<1|1].l ) e[s].sum |=e[s<<1|1].sum ; } void downloat(int i){ if(e[i].add !=0){ ll s = e[i].add ;//不要用int 用ll,作者就在這卡了一天 e[i<<1].sum = s; e[i<<1].add = s; e[i<<1|1].add = s; e[i<<1|1].sum = s; e[i].add = 0; } } void build_up (int rt,int l,int r){ e[rt].l = l;e[rt].r = r; if(l == r){ e[rt].sum = (ll)1<<(clr[dfn[l]]); e[rt].add = 0; return; } int mid = (l+r) >> 1; build_up(rt<<1,l,mid); build_up(rt<<1|1,mid+1,r); e[rt].sum = e[rt<<1].sum | e[rt<<1|1].sum; } void updata(int i,int l,int r,int add){ if(e[i].l >= l && e[i].r <= r) { e[i].sum = (ll)1<<add; e[i].add = (ll)1<<add; return; } int mid = (e[i].l + e[i].r ) >> 1; downloat(i); if(mid >= r)updata(i<<1,l,r,add); else if(mid <l)updata(i<<1|1,l,r,add); else updata(i<<1,l,mid,add),updata(i<<1|1,mid+1,r,add); uploat(i); } ll query(int i,int l,int r) { if(e[i].l >= l && e[i].r <= r){ return e[i].sum ; } downloat(i); int mid = (e[i].l +e[i].r ) >> 1; if(mid >= r) return query(i<<1,l,r); else if(mid<l) return query(i<<1|1,l,r);//熟悉的操作 return query(i<<1,l,mid)|query(i<<1|1,mid+1,r); } ll lowbit(ll x){ return x&-x;//lowbit函式 } int ans; int main(){ n = read(); m = read(); init (); for(int i = 1;i <= n;i ++) clr[i] = read(); for(int i = 1;i <= n - 1;i ++) { int x = read(),y = read(); add(x,y);add(y,x); } dfs(1,0); build_up(1,1,n);//建樹 for(int i = 1;i <= m; i++) { int x = read(); int y; int z; if(x == 1){ y = read();z = read(); updata(1,l[y],r[y],z); } else{ ans = 0;y = read(); ll diet = query(1,l[y],r[y]); while(diet>0){ diet-=lowbit(diet); ans++;//判斷1的個數 } cout<<ans<<endl;//華麗收場 } } return 0; }