zoukankan      html  css  js  c++  java
  • 21.11.16模拟 bzoj3306树

    要求修改树上点权,查询子树内最小值和换根

    对于换根操作,我们不妨分类讨论一下
    设初始的根为1,当前的根为rt,要查询的子树x

    若x==rt,直接输出全局最小值即可

    在以1为根的情况下

    若rt是x的祖先,那么当前的最小值还是在x的子树内
    若x是rt的祖先,那么x原本的子树中到rt的子树就不能要了。在倍增求LCA(rt,x)的时候,求出lca,顺便求出rt,x中距离x最近的节点y,把y的子树删去,就是目前的答案

    const int N = 1e5 + 79;
    struct graph {
    	int head[N], tot, next[N << 1], ver[N << 1];
    	inline void add(int a, int b) {
    		ver[++tot] = b;
    		next[tot] = head[a];
    		head[a] = tot;
    	}
    } G;
    int n, Q;
    int a[N], b[N], rt;
    int dfn[N], siz[N], tim;
    int anc[20][N], dep[N];
    inline void dfs(int x) {
    	dep[x] = dep[anc[0][x]] + 1;
    	dfn[x] = ++tim;
    	b[tim] = a[x];
    	siz[x] = 1;
    	rep(i, 1, 18) {
    		anc[i][x] = anc[i - 1][anc[i - 1][x]];
    	}
    	repg(x) {
    		int y(G.ver[i]);
    		if(y == anc[0][x]) continue;
    		anc[0][y] = x;
    		dfs(y);
    		siz[x] += siz[y];
    	}
    }
    struct SgementTree {
    	int lc[N << 2], rc[N << 2];
    	int mi[N << 2], rt, cnt;
    	inline void build(int &p, int L, int R) {
    		if(!p) p = ++cnt;
    		if(L == R) {
    			mi[p] = b[L];
    			return ;
    		}
    		int mid(L + R >> 1);
    		build(lc[p], L, mid);
    		build(rc[p], mid + 1, R);
    		mi[p] = min(mi[lc[p]], mi[rc[p]]);
    	}
    	inline void change(int &p, int L, int R, int pos, int val) {
    		if(!p) p = ++cnt;
    		if(L == R) {
    			mi[p] = val;
    			return ;
    		}
    		int mid(L + R >> 1);
    		if(pos <= mid) change(lc[p], L, mid, pos, val);
    		else change(rc[p], mid + 1, R, pos, val);
    		mi[p] = min(mi[lc[p]], mi[rc[p]]);
    	}
    	inline int query(int &p, int L, int R, int ll, int rr) {
    		if(!p) return 0;
    		if(ll <= L && rr >= R) {
    			return mi[p];
    		}
    		int mid(L + R >> 1), ans(1e9);
    		if(ll <= mid)ans = min(ans, query(lc[p], L, mid, ll, rr));
    		if(rr > mid) ans = min(ans, query(rc[p], mid + 1, R, ll, rr));
    		return ans;
    	}
    } S;
    #define pii std::pair<int,int>
    inline pii lca(int x, int y) {
    	if(dep[x] < dep[y]) std::swap(x, y);
    	drp(i, 18, 0) {
    		if(dep[anc[i][x]] > dep[y]) {
    			x = anc[i][x];
    		}
    	}
    	if(anc[0][x] == y) return {anc[0][x], x};
    	drp(i, 18, 0) {
    		if(anc[i][x]^anc[i][y]) {
    			x = anc[i][x];
    			y = anc[i][y];
    		}
    	}
    	return {anc[0][x], x};
    }
    
    int main() {
    	freopen("tree.in", "r", stdin);
    	freopen("tree.out", "w", stdout);
    	read(n);
    	read(Q);
    	int f;
    	rep(i, 1, n) {
    		read(f);
    		read(a[i]);
    		if(!f) {
    			rt = i;
    		}
    		G.add(f, i);
    		G.add(i, f);
    	}
    	dfs(rt);
    	S.build(S.rt, 1, n);
    	char op;
    	int x, y;
    	while(Q--) {
    		while( (op = gt()) != 'E' && op != 'V' && op != 'Q');
    		read(x);
    		if(op == 'V') {
    			read(y);
    			S.change(S.rt, 1, n, dfn[x], y);
    		} else if(op == 'E') {
    			rt = x;
    		} else {
    			if(rt == x) {
    				out(S.mi[S.rt], '\n');
    				continue;
    			}
    			pii s = lca(rt, x);
    			if(s.first != x) { 
    				out(S.query(S.rt, 1, n, dfn[x], dfn[x] + siz[x] - 1), '\n');
    			} else {
    				out(min(S.query(S.rt, 1, n, 1, dfn[s.second] - 1), S.query(S.rt, 1, n, dfn[s.second] + siz[s.second] + 1, n)), '\n');
    			}
    		}
    	}
    	return 0;
    }
    

    本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15566277.html

  • 相关阅读:
    HTTP Digest authentication
    HDU 1520 Anniversary party 树形DP
    Servlet过滤器
    Js apply 方法 具体解释
    java 读取固定目录下的文件(和上篇差点儿相同)
    使用nodeitk进行角点检測
    ~/.local/share/Trash/files
    mv,Directory not empty不能目录覆盖
    cp 提示 overwrite 问题
    cv:显示Linux命令运行进度
  • 原文地址:https://www.cnblogs.com/QQ2519/p/15566277.html
Copyright © 2011-2022 走看看