BZOJ3083 遥远的国度 (树链剖分 换根子树求min)
题意
题解
除去树剖模板,问题就是换根。写LCT?要维护子树信息比较麻烦。
树剖仍然可以做。
我们还是按为根树剖。对于询问分一下类,假设当前点为,根为:
- ,直接询问整棵树。
- 不在子树内,则在以为根时的子树和以为根时的子树相同,直接查询子树。
- 在子树内,那么一定可以找到的儿子使得是的子树。那么除去子树的所有点都在在以为根时的子树内。序上查询被的子树分开的两个区间就行了。
找可以倍增,也可以写树剖。树剖见代码。
CODE
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
const LL INF = 1e12;
int n, q, rt, fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt, seq[MAXN];
LL a[MAXN];
inline void link(int u, int v) {
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int fa[MAXN], dep[MAXN], son[MAXN], top[MAXN], dfn[MAXN], sz[MAXN];
int tmr;
void dfs1(int u, int ff) {
dep[u] = dep[fa[u]=ff] + (sz[u]=1);
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != ff) {
dfs1(v, u), sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp;
seq[dfn[u] = ++tmr] = u;
if(son[u]) dfs2(son[u], tp);
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != fa[u] && v != son[u])
dfs2(v, v);
}
LL v[MAXN<<2], lz[MAXN<<2];
inline void upd(int i) { v[i] = min(v[i<<1], v[i<<1|1]); }
inline void pushd(int i) {
if(~lz[i]) {
lz[i<<1] = lz[i<<1|1] = v[i<<1] = v[i<<1|1] = lz[i];
lz[i] = -1;
}
}
void build(int i, int l, int r) {
lz[i] = -1;
if(l == r) { v[i] = a[seq[l]]; return; }
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
upd(i);
}
void modify(int i, int l, int r, int x, int y, LL z) {
if(x <= l && r <= y) {
lz[i] = v[i] = z; return;
}
pushd(i);
int mid = (l + r) >> 1;
if(x <= mid) modify(i<<1, l, mid, x, y, z);
if(y > mid) modify(i<<1|1, mid+1, r, x, y, z);
upd(i);
}
LL query(int i, int l, int r, int x, int y) {
if(x <= l && r <= y) return v[i];
pushd(i);
int mid = (l + r) >> 1; LL re = INF;
if(x <= mid) re = min(re, query(i<<1, l, mid, x, y));
if(y > mid) re = min(re, query(i<<1|1, mid+1, r, x, y));
upd(i); return re;
}
void cover(int u, int v, LL w) {
while(top[u]^top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
modify(1, 1, n, dfn[top[u]], dfn[u], w); u = fa[top[u]];
}
if(dep[u] < dep[v]) swap(u, v);
modify(1, 1, n, dfn[v], dfn[u], w);
}
inline int get(int u, int v) {
while(top[u] ^ top[v]) {
if(fa[top[v]] == u) return top[v];
v = fa[top[v]];
}
return son[u];
}
int main () {
scanf("%d%d", &n, &q);
for(int i = 1, x, y; i < n; ++i)
scanf("%d%d", &x, &y), link(x, y);
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
dfs1(1, 0), dfs2(1, 1);
build(1, 1, n);
scanf("%d", &rt);
int op, a, b; LL c;
while(q--) {
scanf("%d%d", &op, &a);
if(op == 1) rt = a;
else if(op == 2) {
scanf("%d%lld", &b, &c);
cover(a, b, c);
}
else {
if(rt == a) printf("%lld\n", v[1]);
else if(dfn[rt] < dfn[a] || dfn[rt] >= dfn[a]+sz[a]) printf("%lld\n", query(1, 1, n, dfn[a], dfn[a]+sz[a]-1));
else {
int t = get(a, rt); LL ans = INF;
ans = min(ans, query(1, 1, n, 1, dfn[t]-1));
if(dfn[t]+sz[t] < n)
ans = min(ans, query(1, 1, n, dfn[t]+sz[t], n));
printf("%lld\n", ans);
}
}
}
}