luoguP3979 遥远的国度 树链剖分


\(1, 2\)操作没什么好说的

对于\(3\)操作,分三种情况讨论下

\(id = rt\)的情况下,查整棵树的最小值即可

如果\(rt\)\(1\)号点为根的情况下不在\(id\)的子树中,那么查\(1\)号点为根的情况下\(id\)的子树即可

否则,找到\(rt\)\(id\)链中\(id\)的儿子,整棵树去掉这个子树就是\(id\)新的子树


然而我太懒了,不想打倍增

于是我们考虑用树剖来解决这个问题

分两种情况

如果最后\(id\)\(id\)的儿子处于一条重链,那么返回\(son[id]\)

否则,返回最后访问的轻链顶


复杂度\(O(n \log^2 n)\)


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

#define gc getchar
inline int read() {
	int p = 0, w = 1; char c = gc();
	while(c < '0' || c > '9') { if(c == '-') w = -1; c = gc(); }
	while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
	return p * w;
}
	
const int sid = 4e5 + 5;
	
int n, m, rt, id, cnp;
int cap[sid], nxt[sid], node[sid];
int anc[sid], val[sid], grd[sid], ind[sid], dfn[sid];
int sz[sid], dep[sid], cov[sid], fa[sid], son[sid];
	
inline void addedge(int u, int v) {
	nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
}
	
#define cur node[i]
inline void dfs(int o) {
	sz[o] = 1; 
	for(int i = cap[o]; i; i = nxt[i])
		if(cur != fa[o]) {
			fa[cur] = o;
			dep[cur] = dep[o] + 1;
			dfs(cur);
			sz[o] += sz[cur];
			if(sz[cur] > sz[son[o]]) son[o] = cur;
		}
}

inline void dfs(int o, int ac) {
	anc[o] = ac; dfn[o] = ++ id; ind[id] = o;
	if(!son[o]) return;
	dfs(son[o], ac);
	for(int i = cap[o]; i; i = nxt[i])
		if(cur != fa[o] && cur != son[o])
			dfs(cur, cur);
}
	
#define ls (o << 1)
#define rs (o << 1 | 1)
	
inline void build(int o, int l, int r) {
	if(l == r) { val[o] = grd[ind[l]]; return; }
	int mid = (l + r) >> 1;
	build(ls, l, mid); build(rs, mid + 1, r);
	val[o] = min(val[ls], val[rs]);
}
	
inline void pcov(int o, int v) {
	val[o] = cov[o] = v;
}
	
inline void pushcov(int o) {
	if(!cov[o]) return;
	pcov(ls, cov[o]); pcov(rs, cov[o]);
	cov[o] = 0;
}

inline void mdf(int o, int l, int r, int ml, int mr, int v) {
	if(ml > r || mr < l) return;
	if(ml <= l && mr >= r) { pcov(o, v); return; }
	pushcov(o);
	int mid = (l + r) >> 1;
	mdf(ls, l, mid, ml, mr, v);
	mdf(rs, mid + 1, r, ml, mr, v);
	val[o] = min(val[ls], val[rs]);
}

const int inf = 2147483647;
inline int qry(int o, int l, int r, int ml, int mr) {
	if(ml > r || mr < l || ml > mr) return inf;
	if(ml <= l && mr >= r) return val[o];
	pushcov(o);
	int mid = (l + r) >> 1;
	return min(qry(ls, l, mid, ml, mr), qry(rs, mid + 1, r, ml, mr));
}

inline void mdf(int u, int v, int w) {
	int pu = anc[u], pv = anc[v];
	while(pu != pv) {
		if(dep[pu] < dep[pv]) swap(u, v), swap(pu, pv);
		mdf(1, 1, n, dfn[pu], dfn[u], w);
		u = fa[pu]; pu = anc[u];
	}
	if(dep[u] > dep[v]) swap(u, v);
	mdf(1, 1, n, dfn[u], dfn[v], w);
}

inline int up(int o, int top) {
	int po = anc[o], pv = anc[top];
	while(po != pv) {
		if(fa[po] == top) return po;
		o = fa[po]; po = anc[o];
	}
	return son[top];
}

int main() {
	n = read(); m = read();
	rep(i, 2, n) {
		int u = read(), v = read();
		addedge(u, v); addedge(v, u);
	}
	rep(i, 1, n) grd[i] = read();
	dfs(1); dfs(1, 1); build(1, 1, n);
	rt = read();
	rep(i, 1, m) {
		int opt = read();
		if(opt == 1) rt = read();
		else if(opt == 2) {
			int u = read(), v = read(), w = read();
			mdf(u, v, w);
		}
		else {
			int ip = read();
			if(ip == rt) printf("%d\n", val[1]);
			else {
				if(dfn[ip] <= dfn[rt] && dfn[rt] <= dfn[ip] + sz[ip] - 1) {
					int t = up(rt, ip);
					printf("%d\n", min(qry(1, 1, n, 1, dfn[t] - 1), qry(1, 1, n, dfn[t] + sz[t], n)));
				}
				else printf("%d\n", qry(1, 1, n, dfn[ip], dfn[ip] + sz[ip] - 1));
			}
		}
	}
	return 0;
}
posted @ 2018-12-18 22:35  remoon  阅读(145)  评论(0编辑  收藏  举报