@wsndy-xx
2018-05-05T19:56:27.000000Z
字数 2869
阅读 1018
题解
最近做题第一道写完代码直接过样例,然后A掉的,唉
一棵树
每个节点有各自的属性(相同数字代表相同属性)和权值
4中操作
修改节点的属性
修改节点的权值
询问一条路径中所有与起点属性相同的点的价值之和
询问一条路径中所有与起点属性相同的点的最大权职
树上问题转化到链上
当然是树链剖分啦
但是属性不同怎么办
那我们就对每个属性都开一颗线段树
查询时只需找到对应属性的线段树进行查询就可以啦
对每个属性都开线段树???
空间爆炸
我们可以动态开点
(其实这题主要是练一下线段树的动态开点)
这样就可以完美的过掉这道T啦
#include <bits/stdc++.h>
const int N = 1e5 + 10;
#define gc getchar()
int n, T;
int bel[N], data[N], root[N];
int size[N], son[N], topp[N], fa[N], deep[N], tree[N], bef[N], Tree;
int tot, W[N * 20], Max[N * 20], lson[N * 20], rson[N * 20];
inline int read() {
int x = 0; char c = gc;
while(c < '0' || c > '9') c = gc;
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
return x;
}
struct Node {int v, nxt;} G[N << 2];
int now = 1, head[N];
inline void Add(int u, int v) {G[now].v = v; G[now].nxt = head[u]; head[u] = now ++;}
void Dfs_1(int u, int f_, int dep) {
fa[u] = f_; deep[u] = dep; size[u] = 1;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != f_) {
Dfs_1(v, u, dep + 1);
size[u] += size[v];
if(size[son[u]] < size[v]) son[u] = v;
}
}
}
void Dfs_2(int u, int tp) {
topp[u] = tp; tree[u] = ++ Tree; bef[Tree] = u;
if(!son[u]) return ;
Dfs_2(son[u], tp);
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u] && v != son[u]) Dfs_2(v, v);
}
}
void Poi_G(int l, int r, int & jd, int x, int w) {
if(!jd) jd = ++ tot;
W[jd] += w;
if(l == r) {Max[jd] += w; return ;}
int mid = (l + r) >> 1;
if(x <= mid) Poi_G(l, mid, lson[jd], x, w);
else Poi_G(mid + 1, r, rson[jd], x, w);
Max[jd] = std:: max(Max[lson[jd]], Max[rson[jd]]);
}
int Ans;
void Sec_A_sum(int l, int r, int jd, int x, int y) {
if(! jd) return ;
if(x <= l && r <= y) {Ans += W[jd]; return ;}
int mid = (l + r) >> 1;
if(x <= mid) Sec_A_sum(l, mid, lson[jd], x, y);
if(y > mid ) Sec_A_sum(mid + 1, r, rson[jd], x, y);
}
void Sec_A_max(int l, int r, int jd, int x, int y) {
if(! jd) return ;
if(x <= l && r <= y) {Ans = std:: max(Ans, Max[jd]); return ;}
int mid = (l + r) >> 1;
if(x <= mid) Sec_A_max(l, mid, lson[jd], x, y);
if(y > mid ) Sec_A_max(mid + 1, r, rson[jd], x, y);
}
inline int Sec_A_Imp(int x, int y, int Rt) {
int tp1 = topp[x], tp2 = topp[y], ret(0);
while(tp1 != tp2) {
if(deep[tp1] < deep[tp2]) std:: swap(tp1, tp2), std:: swap(x, y);
Ans = 0;
Sec_A_sum(1, n, root[Rt], tree[tp1], tree[x]);
ret += Ans;
x = fa[tp1];
tp1 = topp[x];
}
Ans = 0;
if(deep[x] < deep[y]) std:: swap(x, y);
Sec_A_sum(1, n, root[Rt], tree[y], tree[x]);
ret += Ans;
return ret;
}
inline int Sec_A_Imp2(int x, int y, int Rt) {
int tp1 = topp[x], tp2 = topp[y]; Ans = 0;
while(tp1 != tp2) {
if(deep[tp1] < deep[tp2]) std:: swap(tp1, tp2), std:: swap(x, y);
Sec_A_max(1, n, root[Rt], tree[tp1], tree[x]);
x = fa[tp1];
tp1 = topp[x];
}
if(deep[x] < deep[y]) std:: swap(x, y);
Sec_A_max(1, n, root[Rt], tree[y], tree[x]);
return Ans;
}
int main() {
n = read(); T = read();
for(int i = 1; i <= n; i ++) data[i] = read(), bel[i] = read();
for(int i = 1; i <= n; i ++) head[i] = -1;
for(int i = 1; i < n; i ++) {
int a = read(), b = read();
Add(a, b); Add(b, a);
}
Dfs_1(1, 0, 1);
Dfs_2(1, 1);
for(int i = 1; i <= n; i ++) Poi_G(1, n, root[bel[i]], tree[i], data[i]);
while(T --) {
std:: string opt; std:: cin >> opt;
int x = read(), y = read();
if(opt == "CC") Poi_G(1, n, root[bel[x]], tree[x], -data[x]),
Poi_G(1, n, root[y], tree[x], data[x]), bel[x] = y;
else if(opt == "CW") Poi_G(1, n, root[bel[x]], tree[x], y - data[x]), data[x] = y;
else if(opt == "QS") std:: cout << Sec_A_Imp(x, y, bel[x]) << "\n";
else std:: cout << Sec_A_Imp2(x, y, bel[x]) << "\n";
}
return 0;
}