1. 程式人生 > >[SDOI2017]樹點塗色

[SDOI2017]樹點塗色

down num continue break lct left std using tdi

題意

有操作:

  • 1 $x$

把點 $x$ 到根節點的路徑上所有的點染上一種沒有用過的新顏色。

  • 2 $x$ $y$

求 $x$ 到 $y$ 的路徑的權值。

  • 3 $x$

在以 $x$ 為根的子樹中選擇一個點,使得這個點到根節點的路徑權值最大,求最大權值。

題解

因為觀察到一個顏色一定是一條向根節點的鏈,也就是說一條鏈代表了一個信息,那麽就可以用 $LCT$ 中的一個 $Splay$ 去維護一條鏈(顏色)

那麽一個節點的“權值”即為它到根節點經過的輕邊個數,求出單點“權值”後,直接用差分即可解決操作 $2$

用樹剖可以解決,但是這樣的話連 $LCT$ 都不用了,同理,想到 $dfs$ 序,在 $Access$ 操作的時候刪掉一條輕邊並且增加一條輕邊,答案有修改的只有該輕邊端點包含的子樹,那麽直接線段樹修改就好了

代碼

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 #define lson root << 1
  6 #define rson root << 1 | 1
  7 
  8 using namespace std;
  9 
 10 const int MAXN = 1e05 + 10;
 11 const int MAXM = 1e05 + 10;
 12 
 13 struct LinkedForwardStar {
14 int to; 15 16 int next; 17 } ; 18 19 LinkedForwardStar Link[MAXM << 1]; 20 int Head[MAXN]= {0}; 21 int size = 0; 22 23 void Insert (int u, int v) { 24 Link[++ size].to = v; 25 Link[size].next = Head[u]; 26 27 Head[u] = size; 28 } 29 30 const
int Root = 1; 31 32 int Deep[MAXN]; 33 int Size[MAXN]= {0}; 34 int Dfn[MAXN], Rank[MAXN]; 35 int dfsord = 0; 36 37 int Maxv[MAXN << 2]= {0}; 38 int lazy[MAXN << 2]= {0}; 39 void pushdown (int root) { 40 if (lazy[root]) { 41 Maxv[lson] += lazy[root]; 42 Maxv[rson] += lazy[root]; 43 lazy[lson] += lazy[root]; 44 lazy[rson] += lazy[root]; 45 lazy[root] = 0; 46 } 47 } 48 void Build (int root, int left, int right) { 49 if (left == right) { 50 Maxv[root] = Deep[Rank[left]]; 51 return ; 52 } 53 int mid = (left + right) >> 1; 54 Build (lson, left, mid); 55 Build (rson, mid + 1, right); 56 Maxv[root] = max (Maxv[lson], Maxv[rson]); 57 } 58 void Modify (int root, int left, int right, int L, int R, int delta) { 59 if (L <= left && right <= R) { 60 Maxv[root] += delta; 61 lazy[root] += delta; 62 return ; 63 } 64 pushdown (root); 65 int mid = (left + right) >> 1; 66 if (L <= mid) 67 Modify (lson, left, mid, L, R, delta); 68 if (R > mid) 69 Modify (rson, mid + 1, right, L, R, delta); 70 Maxv[root] = max (Maxv[lson], Maxv[rson]); 71 } 72 int Query (int root, int left, int right, int L, int R) { 73 if (L <= left && right <= R) 74 return Maxv[root]; 75 pushdown (root); 76 int mid = (left + right) >> 1; 77 int maxv = 0; 78 if (L <= mid) 79 maxv = max (maxv, Query (lson, left, mid, L, R)); 80 if (R > mid) 81 maxv = max (maxv, Query (rson, mid + 1, right, L, R)); 82 return maxv; 83 } 84 85 int N, M; 86 87 int father[MAXN]= {0}; 88 int son[MAXN][2]= {0}; 89 int isroot (int p) { 90 return son[father[p]][0] != p && son[father[p]][1] != p; 91 } 92 int sonbel (int p) { 93 return son[father[p]][1] == p; 94 } 95 void rotate (int p) { 96 int fa = father[p], anc = father[fa]; 97 int s = sonbel (p); 98 son[fa][s] = son[p][s ^ 1]; 99 if (son[fa][s]) 100 father[son[fa][s]] = fa; 101 if (! isroot (fa)) 102 son[anc][sonbel (fa)] = p; 103 father[p] = anc; 104 son[p][s ^ 1] = fa, father[fa] = p; 105 } 106 void splay (int p) { 107 for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p]) 108 if (! isroot (fa)) 109 sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p); 110 } 111 int findroot (int p) { 112 while (son[p][0]) 113 p = son[p][0]; 114 return p; 115 } 116 void Access (int p) { 117 for (int tp = 0; p; tp = p, p = father[p]) { 118 splay (p); 119 if (son[p][1]) { 120 int rt = findroot (son[p][1]); 121 Modify (Root, 1, N, Dfn[rt], Dfn[rt] + Size[rt] - 1, 1); 122 } 123 son[p][1] = tp; 124 if (son[p][1]) { 125 int rt = findroot (son[p][1]); 126 Modify (Root, 1, N, Dfn[rt], Dfn[rt] + Size[rt] - 1, - 1); 127 } 128 } 129 } 130 131 int ances[MAXN][20]; 132 void DFS (int root, int fa) { 133 Dfn[root] = ++ dfsord, Rank[dfsord] = root; 134 ances[root][0] = father[root] = fa; 135 for (int j = 1; j <= 18; j ++) { 136 if (! ances[root][j - 1]) 137 break; 138 ances[root][j] = ances[ances[root][j - 1]][j - 1]; 139 } 140 Size[root] = 1; 141 for (int i = Head[root]; i; i = Link[i].next) { 142 int v = Link[i].to; 143 if (v == fa) 144 continue; 145 Deep[v] = Deep[root] + 1; 146 DFS (v, root); 147 Size[root] += Size[v]; 148 } 149 } 150 151 int LCA (int x, int y) { 152 if (Deep[x] < Deep[y]) 153 swap (x, y); 154 int fx = x, fy = y; 155 for (int j = 18; j >= 0; j --) 156 if (Deep[ances[fx][j]] >= Deep[fy]) 157 fx = ances[fx][j]; 158 if (fx == fy) 159 return fy; 160 for (int j = 18; j >= 0; j --) 161 if (ances[fx][j] != ances[fy][j]) { 162 fx = ances[fx][j]; 163 fy = ances[fy][j]; 164 } 165 return ances[fx][0]; 166 } 167 168 int getnum () { 169 int num = 0; 170 char ch = getchar (); 171 172 while (! isdigit (ch)) 173 ch = getchar (); 174 while (isdigit (ch)) 175 num = (num << 3) + (num << 1) + ch - 0, ch = getchar (); 176 177 return num; 178 } 179 180 int main () { 181 N = getnum (), M = getnum (); 182 for (int i = 1; i < N; i ++) { 183 int u = getnum (), v = getnum (); 184 Insert (u, v), Insert (v, u); 185 } 186 Deep[Root] = 1, DFS (Root, 0); 187 Build (Root, 1, N); 188 for (int i = 1; i <= M; i ++) { 189 int opt = getnum (); 190 if (opt == 1) { 191 int p = getnum (); 192 Access (p); 193 } 194 else if (opt == 2) { 195 int x = getnum (), y = getnum (); 196 int lca = LCA (x, y); 197 int qx = Query (Root, 1, N, Dfn[x], Dfn[x]); 198 int qy = Query (Root, 1, N, Dfn[y], Dfn[y]); 199 int qlca = Query (Root, 1, N, Dfn[lca], Dfn[lca]); 200 int ans = qx + qy - (qlca << 1) + 1; 201 printf ("%d\n", ans); 202 } 203 else if (opt == 3) { 204 int p = getnum (); 205 int ans = Query (Root, 1, N, Dfn[p], Dfn[p] + Size[p] - 1); 206 printf ("%d\n", ans); 207 } 208 } 209 210 return 0; 211 } 212 213 /* 214 5 6 215 1 2 216 2 3 217 3 4 218 3 5 219 2 4 5 220 3 3 221 1 4 222 2 4 5 223 1 5 224 2 4 5 225 */

[SDOI2017]樹點塗色