BZOJ3083 遥远的国度 (树链剖分 换根子树求min)

题意

传送门

题解

除去树剖模板,问题就是换根。写LCT?要维护子树信息比较麻烦。

树剖仍然可以做。

我们还是按11为根树剖。对于询问分一下类,假设当前点为uu,根为rtrt

  • u=rtu=rt,直接询问整棵树。
  • rtrt不在uu子树内,则uu在以rtrt为根时的子树和以11为根时的子树相同,直接查询子树。
  • rtrtuu子树内,那么一定可以找到uu的儿子vv使得rtrtvv的子树。那么除去vv子树的所有点都在uu在以rtrt为根时的子树内。dfsdfs序上查询被vv的子树分开的两个区间就行了。

vv可以倍增,也可以写树剖。树剖见代码。

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);
			}
		}
	}
}

posted @ 2019-12-14 14:50  _Ark  阅读(139)  评论(0编辑  收藏  举报