树链剖分模板(BZOJ3083)
实现了路径修改,子树查询,及换根。
换根其实很简单,分三种情况讨论,画画图就明白了。
#include <cstdio> #include <algorithm> using namespace std; #define m ((L+R)>>1) #define lc o<<1 #define rc o<<1|1 #define ls lc,L,m #define rs rc,m+1,R const int N = 100005, M = 200005; int n,q,e,x,y,z,op,sd,tt;
int a[N],d[N],f[N],p[N],s[N],bg[N],ed[N],sz[N],tp[N],hd[N],nxt[M],to[M],v[N<<2],mn[N<<2]; void add(int x, int y) {to[++e] = y, nxt[e] = hd[x], hd[x] = e;} void dfs(int x) { int mx = 0; sz[x] = 1; for(int i = hd[x]; i; i = nxt[i]) if(!d[to[i]]) { d[to[i]] = d[x]+1, f[to[i]] = x, dfs(to[i]), sz[x] += sz[to[i]]; if(sz[to[i]] > mx) mx = sz[to[i]], s[x] = to[i]; } } void dfs2(int x) { bg[x] = ++tt, p[tt] = x; if(s[x]) tp[s[x]] = tp[x], dfs2(s[x]); for(int i = hd[x]; i; i = nxt[i]) if(to[i] != f[x] && to[i] != s[x]) tp[to[i]] = to[i], dfs2(to[i]); ed[x] = tt; } void bd(int o, int L, int R) { if(L == R) {mn[o] = a[p[L]]; return;} bd(ls), bd(rs), mn[o] = min(mn[lc], mn[rc]); } void pd(int o) { if(!v[o]) return; mn[lc] = mn[rc] = v[o], v[lc] = v[rc] = v[o], v[o] = 0; } void gai(int o, int L, int R, int l, int r, int x) { if(L >= l && R <= r) {v[o] = mn[o] = x; return;} pd(o); if(l <= m) gai(ls, l, r, x); if(r > m) gai(rs, l, r, x); mn[o] = min(mn[lc], mn[rc]); } int qry(int o, int L, int R, int l, int r) { if(L >= l && R <= r) return mn[o]; pd(o); if(r <= m) return qry(ls, l, r); if(l > m) return qry(rs, l, r); return min(qry(ls, l, r), qry(rs, l, r)); } void upd(int x, int y, int z) { while(tp[x]^tp[y]) { if(d[tp[x]] < d[tp[y]]) swap(x, y); gai(1, 1, n, bg[tp[x]], bg[x], z), x = f[tp[x]]; } if(d[x] < d[y]) swap(x, y); gai(1, 1, n, bg[y], bg[x], z); } int main() { scanf("%d%d", &n, &q); for(int i = 1; i < n; i++) scanf("%d%d", &x, &y), add(x, y), add(y, x); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); scanf("%d", &sd), d[sd] = 1, tp[sd] = sd, dfs(sd), dfs2(sd), bd(1, 1, n); while(q--) { scanf("%d%d", &op, &x); if(op == 1) sd = x; else if(op == 2) scanf("%d%d", &y, &z), upd(x, y, z); else { if(sd == x) printf("%d\n", mn[1]); else if(bg[x] > bg[sd] || ed[x] < bg[sd]) printf("%d\n", qry(1,1,n,bg[x],ed[x])); else { for(int i = hd[x]; i; i = nxt[i]) if(to[i] != f[x] && bg[to[i]] <= bg[sd] && ed[to[i]] >= bg[sd]) { int ans = qry(1,1,n,1,bg[to[i]]-1); if(ed[to[i]]^n) ans = min(ans, qry(1,1,n,ed[to[i]]+1,n)); printf("%d\n", ans); break; } } } } return 0; }