1. 程式人生 > >|BZOJ 3531|樹鏈剖分|動態開點線段樹|[Sdoi2014]旅行

|BZOJ 3531|樹鏈剖分|動態開點線段樹|[Sdoi2014]旅行

樹剖以後每個宗教建立一棵線段樹,節點太多用傳統方法開陣列肯定不行,這裡進行改進,使用了動態開點線段樹,即需要這個點再開這個點。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ms(i, j) memset(i, j, sizeof i)
#define ll long long
using namespace std;

const int MAXN = 1e5 + 5, MAXTN = 10000000 + 5;

vector<int
>
G[MAXN]; int n, q, wi[MAXN], ci[MAXN]; int top[MAXN], fa[MAXN], son[MAXN], siz[MAXN], p[MAXN], dep[MAXN], pre; int lt[MAXTN], rt[MAXTN], root[MAXN], nd; ll sumv[MAXTN], maxv[MAXTN]; //樹剖部分 void dfs1(int u, int pa) { dep[u] = dep[pa] + 1, fa[u] = pa, siz[u] = 1; for (int i=0;i<G[u].size();i++) { int
v = G[u][i]; if (v!=pa) { dfs1(v, u); siz[u] += siz[v]; if (son[u]==-1||siz[v]>siz[son[u]]) son[u] = v; } } } void dfs2(int u, int chain) { p[u] = ++pre, top[u] = chain; if (son[u]!=-1) { dfs2(son[u], chain); for (int
i=0;i<G[u].size();i++) { int v = G[u][i]; if (v!=fa[u]&&v!=son[u]) { dfs2(v, v); } } } } //線段樹部分 #define M ((l+r)>>1) void pushup(int o) { sumv[o] = sumv[lt[o]] + sumv[rt[o]]; maxv[o] = max(maxv[lt[o]], maxv[rt[o]]); } void update(int o, int l, int r, int p, ll w) { if (l==r) { sumv[o] = maxv[o] = w; return ; } if (p<=M) { if (!lt[o]) lt[o] = ++nd; update(lt[o], l, M, p, w); } else if (M<p) { if (!rt[o]) rt[o] = ++nd; update(rt[o], M+1, r, p, w); } pushup(o); } ll queryMax(int o, int l, int r, int x, int y) { ll ret = 0; if (x<=l&&r<=y) { return maxv[o]; } if (x<=M) { if (lt[o]) ret = max(ret, queryMax(lt[o], l, M, x, y)); } if (M<y) { if (rt[o]) ret = max(ret, queryMax(rt[o], M+1, r, x, y)); } return ret; } ll querySum(int o, int l, int r, int x, int y) { ll ret = 0; if (x<=l&&r<=y) { return sumv[o]; } if (x<=M) { if (lt[o]) ret += querySum(lt[o], l, M, x, y); } if (M<y) { if (rt[o]) ret += querySum(rt[o], M+1, r, x, y); } return ret; } //樹剖找值 ll findMax(int u, int v, int rt) { ll ret = 0;int f1 = top[u], f2 = top[v]; while (f1!=f2) { if (dep[f1]<dep[f2]) swap(f1, f2), swap(u, v); ret = max(ret, queryMax(rt, 1, n, p[f1], p[u])); u = fa[f1]; f1 = top[u]; } if (dep[u]<dep[v]) swap(u, v); return max(ret, queryMax(rt, 1, n, p[v], p[u])); } ll findSum(int u, int v, int rt) { ll ret = 0;int f1 = top[u], f2 = top[v]; while (f1!=f2) { if (dep[f1]<dep[f2]) swap(f1, f2), swap(u, v); ret += querySum(rt, 1, n, p[f1], p[u]); u = fa[f1]; f1 = top[u]; } if (dep[u]<dep[v]) swap(u, v); return ret + querySum(rt, 1, n, p[v], p[u]); } //主程式 void clear() { pre = nd = 0; ms(sumv, 0), ms(maxv, 0), ms(lt, 0), ms(rt, 0), ms(root, 0); for (int i=0;i<=n;i++) { G[i].clear(); top[i] = fa[i] = siz[i] = p[i] = dep[i] = 0; son[i] = -1; } } void init() { clear(); for (int i=1;i<=n;i++) scanf("%d%d", &wi[i], &ci[i]); for (int i=1;i<n;i++) { int x, y; scanf("%d%d", &x, &y); G[x].push_back(y), G[y].push_back(x); } } void solve() { dfs1(1, 0), dfs2(1, 1); for (int i=1;i<=n;i++) { if (!root[ci[i]]) root[ci[i]] = ++nd; update(root[ci[i]], 1, n, p[i], wi[i]); } char ch[10]; for (int i=1;i<=q;i++) { scanf("%s", ch); if (ch[0]=='C') { if (ch[1]=='C') {//CC int x, c; scanf("%d%d", &x, &c); update(root[ci[x]], 1, n, p[x], 0); ci[x] = c; update(root[c], 1, n, p[x], wi[x]); } else {//CW int x, w; scanf("%d%d", &x, &w); wi[x] = w; update(root[ci[x]], 1, n, p[x], w); } } else if (ch[0]=='Q') { int x, y; scanf("%d%d", &x, &y); if (ch[1]=='S') {//QS printf("%lld\n", findSum(x,y,root[ci[x]])); } else {//QM printf("%lld\n", findMax(x,y,root[ci[x]])); } } } } int main() { #ifndef ONLINE_JUDGE freopen("1.in", "r", stdin);freopen("1.out", "w", stdout); #endif while (scanf("%d%d", &n, &q)==2) init(), solve(); return 0; }