BZOJ 3083: 遥远的国度

树剖
可以不用换根
若根在查询的点的子树内
那么查询的就是查询的点删去根所在的子树,即为两个区间
否则就还是直接查子树

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int cnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++cnt]=v;ne[cnt]=head[u];head[u]=cnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int cnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++cnt]=v;ne[cnt]=head[u];c[cnt]=w;head[u]=cnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}
const int INF = 2147483647;
const int N = 1e5 + 7;
Edg
int n, m, val[N], sz[N], son[N], in[N], dfn, root, fa[N], dep[N];
int top[N], a[N];

void dfs1(int u, int f) {
	fa[u] = f; dep[u] = dep[f] + 1;
	sz[u] = 1;
	es(u, i, v) {
		if (v == f) continue;
		dfs1(v, u);
		sz[u] += sz[v];
		if (sz[v] > sz[son[u]]) 
			son[u] = v;
	}
}
void dfs2(int u, int tp) {
	in[u] = ++dfn; a[dfn] = val[u];
	top[u] = tp;
	if (!son[u]) return;
	dfs2(son[u], tp);
	es(u, i, v) {
		if (v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}
int lazy[N * 4], mn[N * 4];
void build(int p, int l, int r) {
	if (l == r) {
		mn[p] = a[l];
		return;
	}
	build(lp, l, mid); build(rp, mid + 1, r);
	mn[p] = std::min(mn[lp], mn[rp]);
}
inline void tag(int p, int v) {
	mn[p] = lazy[p] = v;
}
inline void pushdown(int p) {
	if (!lazy[p]) return;
	tag(lp, lazy[p]), tag(rp, lazy[p]);
	lazy[p] = 0;
}
void update(int p, int l, int r, int x, int y, int v) {
	if (x <= l && y >= r) return tag(p, v);
	pushdown(p);
	if (x <= mid) update(lp, l, mid, x, y, v);
	if (y > mid) update(rp, mid + 1, r, x, y, v);
	mn[p] = std::min(mn[lp], mn[rp]);
}
int query(int p, int l, int r, int x, int y) {
	if (x > y) return INF;
	if (x <= l && y >= r) return mn[p];
	pushdown(p);
	if (y <= mid) return query(lp, l, mid, x, y);
	if (x > mid) return query(rp, mid + 1, r, x, y);
	return std::min(query(lp, l, mid, x, y), query(rp, mid + 1, r, x, y));
}
int find(int rt, int u) {
	while (top[u] != top[rt]) {
		if (fa[top[u]] == rt) return top[u];
		u = fa[top[u]];
	}
	return son[rt];
}
void solve(int u, int v, int w) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
		update(1, 1, n, in[top[u]], in[u], w);
		u = fa[top[u]];
	}
	if (dep[u] > dep[v]) std::swap(u, v);
	update(1, 1, n, in[u], in[v], w);
}

int main() {
	n = _(), m = _();
	rep(i, 1, n) {
		int u = _(), v = _();
		add(u, v);
	}
	rep(i, 1, n + 1) val[i] = _();
	root = _();
	dfs1(root, 0); dfs2(root, root);
	build(1, 1, n);
	rep(i, 0, m) {
		int opt = _();
		if (opt == 1) root = _();
		else if (opt == 2) {
			int p1 = _(), p2 = _(), v = _();
			solve(p1, p2, v);
		} else {
			int u = _();
			if (u == root) {
				printf("%d\n", query(1, 1, n, 1, n));
				continue;
			}
			if (in[root] > in[u] && in[root] < in[u] + sz[u]) {
				int v = find(u, root);
				printf("%d\n", std::min(query(1, 1, n, 1, in[v] - 1), query(1, 1, n, in[v] + sz[v], n)));
			} else {
				printf("%d\n", query(1, 1, n, in[u], in[u] + sz[u] - 1));
			}
		}
	}
}
posted @ 2020-02-20 00:29  Mrzdtz220  阅读(142)  评论(0)    收藏  举报