bzoj 3531 [Sdoi2014]旅行
题意:维护一棵树,每个结点都有一个种类和一个权值,支持单点修改种类或权值、询问链上某一种类的权值和或最大值
思路:开 c 棵线段树,每一棵代表一个宗教,然后树剖
1 #include <cstdio> 2 #include <string> 3 #include <vector> 4 5 const int N = 1e5 + 10; 6 7 int dfs_clock; 8 9 struct Edge{ 10 int to; 11 }; 12 std::vector<Edge> edges; 13 std::vector<int> G[N]; 14 15 struct Node { 16 int size, deep, pos, top, fa, son, w, c; 17 } a[N]; 18 19 int max(int x, int y) { 20 if (x >= y) return x; 21 return y; 22 } 23 24 void swap(int &x, int & y) { 25 x ^= y, y ^= x, x ^= y; 26 } 27 28 void AddEdge(int from, int to) { 29 G[from].push_back(edges.size()); 30 edges.push_back((Edge){to}); 31 } 32 33 int read() { 34 int x = 0, f = 1; 35 char c = getchar(); 36 while (!isdigit(c)) { 37 if (c == ‘-‘) f = -1; 38 c = getchar(); 39 } 40 while (isdigit(c)) { 41 x = (x << 3) + (x << 1) + (c ^ 48); 42 c = getchar(); 43 } 44 return x * f; 45 } 46 47 struct segtree { 48 segtree *ls, *rs; 49 int sum, mx; 50 void maintain() { 51 sum = mx = 0; 52 if (ls != NULL) { 53 sum += ls->sum; 54 mx = max(mx, ls->mx); 55 } 56 if (rs != NULL) { 57 sum += rs->sum; 58 mx = max(mx, rs->mx); 59 } 60 } 61 segtree() {ls = rs = NULL, sum = mx = 0;} 62 } *tree[N]; 63 64 typedef segtree sgt; 65 66 void dfs1(int cur, int father, int depth) { 67 a[cur].size = 1, a[cur].deep = depth, a[cur].fa = father, a[cur].son = 0; 68 int size = G[cur].size(); 69 for (int i = 0; i < size; ++ i) { 70 int nx = edges[G[cur][i]].to; 71 if (nx != father) { 72 dfs1(nx, cur, depth + 1); 73 a[cur].size += a[nx].size; 74 if (a[nx].size > a[a[cur].son].size) 75 a[cur].son = nx; 76 } 77 } 78 } 79 80 void dfs2(int cur, int top) { 81 a[cur].top = top, a[cur].pos = ++dfs_clock; 82 if (a[cur].son) dfs2(a[cur].son, top); 83 int size = G[cur].size(); 84 for (int i = 0; i < size; ++ i) { 85 int nx = edges[G[cur][i]].to; 86 if (nx != a[cur].fa && nx != a[cur].son) 87 dfs2(nx, nx); 88 } 89 } 90 91 void insert(sgt* &cur, int l, int r, int pos, int val) { 92 if (cur == NULL) cur = new segtree(); 93 if (l == r) { 94 cur->sum = cur->mx = val; 95 return; 96 } 97 int mid = l + ((r - l) >> 1); 98 if (pos <= mid) insert(cur->ls, l, mid, pos, val); 99 else insert(cur->rs, mid + 1, r, pos, val); 100 cur -> maintain(); 101 } 102 103 void erase(sgt* &cur, int l, int r, int pos) { 104 if (cur == NULL) return; 105 if (l == r) { 106 delete cur; cur = NULL; 107 return; 108 } 109 int mid = l + ((r - l) >> 1); 110 if (pos <= mid) erase(cur->ls, l, mid, pos); 111 else erase(cur->rs, mid + 1, r, pos); 112 if (cur->ls == NULL && cur->rs == NULL) { 113 delete cur; cur = NULL; 114 } else { 115 cur -> maintain(); 116 } 117 } 118 119 int Q_max(sgt* &cur, int l, int r, int L, int R) { 120 if (cur == NULL) return 0; 121 if (L <= l && r <= R) return cur->mx; 122 int mid = l + ((r - l) >> 1), ans = 0; 123 if (L <= mid) ans = max(ans, Q_max(cur->ls, l, mid, L, R)); 124 if (mid < R) ans = max(ans, Q_max(cur->rs, mid + 1, r, L, R)); 125 return ans; 126 } 127 128 int Q_sum(sgt* &cur, int l, int r, int L, int R) { 129 if (cur == NULL) return 0; 130 if (L <= l && r <= R) return cur->sum; 131 int mid = l + ((r - l) >> 1), ans = 0; 132 if (L <= mid) ans += Q_sum(cur->ls, l, mid, L, R); 133 if (mid < R) ans += Q_sum(cur->rs, mid + 1, r, L, R); 134 return ans; 135 } 136 137 int chain_max(sgt* &cur, int x, int y) { 138 int ans = 0; 139 while (a[x].top != a[y].top) { 140 if (a[a[x].top].deep < a[a[y].top].deep) swap(x, y); 141 ans = max(ans, Q_max(cur, 1, dfs_clock, a[a[x].top].pos, a[x].pos)); 142 x = a[a[x].top].fa; 143 } 144 if (a[x].deep > a[y].deep) swap(x, y); 145 ans = max(ans, Q_max(cur, 1, dfs_clock, a[x].pos, a[y].pos)); 146 return ans; 147 } 148 149 int chain_sum(sgt* &cur, int x, int y) { 150 int ans = 0; 151 while (a[x].top != a[y].top) { 152 if (a[a[x].top].deep < a[a[y].top].deep) swap(x, y); 153 ans += Q_sum(cur, 1, dfs_clock, a[a[x].top].pos, a[x].pos); 154 x = a[a[x].top].fa; 155 } 156 if (a[x].deep > a[y].deep) swap(x, y); 157 ans += Q_sum(cur, 1, dfs_clock, a[x].pos, a[y].pos); 158 return ans; 159 } 160 161 int main() { 162 int n = read(), m = read(); 163 for (int i = 1; i <= n; ++ i) { 164 a[i].w = read(), a[i].c = read(); 165 } 166 for (int i = 1; i < n; ++ i) { 167 int u = read(), v = read(); 168 AddEdge(u, v); AddEdge(v, u); 169 } 170 dfs1(1, 0, 1); dfs2(1, 1); 171 for (int i = 1; i <= n; ++ i) { 172 insert(tree[a[i].c], 1, n, a[i].pos, a[i].w); 173 } 174 while (m --) { 175 char op = getchar(), t = getchar(); 176 int x = read(), y = read(); 177 if (op == ‘C‘) { 178 if (t == ‘C‘) { 179 erase(tree[a[x].c], 1, n, a[x].pos); 180 insert(tree[y], 1, n, a[x].pos, a[x].w); 181 a[x].c = y; 182 } else { 183 insert(tree[a[x].c], 1, n, a[x].pos, y); 184 a[x].w = y; 185 } 186 } else { 187 if (t == ‘S‘) { 188 printf("%d\n", chain_sum(tree[a[x].c], x, y)); 189 } else { 190 printf("%d\n", chain_max(tree[a[x].c], x, y)); 191 } 192 } 193 } 194 return 0; 195 }
bzoj 3083 遥远的国度
题意:维护一棵树,支持换根、树链覆盖、查询子树最小值
思路:仅当根节点在某个询问的子树上时才对答案有影响:若询问的结点为根,则查询子树;若询问结点为根的祖先,则查询该节点离根最近的儿子的子树的补集