• Codeforces 916E Jamie and Tree (换根讨论)


    题目链接  Jamie and Tree

    题意  给定一棵树,现在有下列操作:

       $1$、把当前的根换成$v$;$2$、找到最小的同时包含$u$和$v$的子树,然后把这棵子树里面的所有点的值加$x$;

       $3$、查询以$v$为根的子树的点权之和。

    这道题其他都是常规操作,就是当前根结点为$cnt$的时候求$x$和$y$的$LCA$(操作$2$要用到)

    我们假定解题的时候根一直不变(我一般都设$1$为根结点)

    答案为$LCA(x,y)$ $xor$ $LCA(x, cnt)$ $xor$ $LCA(y, cnt)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define lson		i << 1, L, mid
    #define rson		i << 1 | 1, mid + 1, R
    
    typedef long long LL;
    
    const int N = 1e5 + 10;
    const int ass = 4e5;
    
    vector <int> v[N];
    
    int ti;
    int tot;
    int n, m;
    int fp[N];
    int deep[N], f[N], st[N], ed[N], father[N], sz[N], son[N];
    int top[N];
    int cnt;
    
    LL a[N];
    LL sum[N << 2], lazy[N << 2];
    
    
    void dfs1(int x, int fa, int dep){
    	deep[x] = dep;
    	father[x] = fa;
    	son[x] = 0;
    	sz[x] = 1;
    	st[x] = ++ti;
    
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs1(u, x, dep + 1);
    		sz[x] += sz[u];
    		if (sz[son[x]] < sz[u]) son[x] = u;
    	}
    	ed[x] = ti;
    }
    
    void dfs2(int x, int tp){
    	top[x] = tp;
    	f[x] = ++tot;
    	fp[f[x]] = x;
    	if (son[x]) dfs2(son[x], tp);
    	for (auto u : v[x]){
    		if (u == father[x] || u == son[x]) continue;
    		dfs2(u, u);
    	}
    }
    
    int LCA(int x, int y){
    	for (; top[x] ^ top[y]; ){
    		if (deep[top[x]] < deep[top[y]]) swap(x, y);
    		x = father[top[x]];
    	}
    
    	return deep[x] > deep[y] ? y : x;
    }
    
    int twz(int x, int y){
    	int t;
    	for (; top[x] ^ top[y]; ) t = top[y], y = father[top[y]];
    	return x == y ? t : son[x];
    }
    
    inline void pushup(int i){
    	sum[i] = sum[i << 1] + sum[i << 1 | 1];
    }
    
    inline void pushdown(int i, int L, int R){
    	if (L == R) return;
    	int mid = (L + R) >> 1;
    	lazy[i << 1] += 1ll * lazy[i];
    	sum[i << 1]  += 1ll * lazy[i] * (mid - L + 1);
    	lazy[i << 1 | 1] += 1ll * lazy[i];
    	sum[i << 1 | 1] += 1ll * lazy[i] * (R - mid);
    	lazy[i] = 0;
    }
    
    
    void build(int i, int L, int R){
    	if (L == R){ sum[i] = 1ll * a[fp[L]]; return; }
    	int mid = (L + R) >> 1;
    	build(lson);
    	build(rson);
    	pushup(i);
    }
    
    void update(int i, int L, int R, int l, int r, LL val){
    	if (l == L && R == r){
    		sum[i]  += 1ll * val * (R - L + 1);
    		lazy[i] += 1ll * val;
    		return ;
    	}
    
    	pushdown(i, L, R);
    	int mid = (L + R) >> 1;
    	if (r <= mid) update(lson, l, r, val);
    	else if (l > mid) update(rson, l, r, val);
    	else{
    		update(lson, l, mid, val);
    		update(rson, mid + 1, r, val);
    	}
    
    	pushup(i);
    }
    
    LL query(int i, int L, int R, int l, int r){
    	pushdown(i, L, R);
    	if (L == l && R == r) return sum[i];
    	int mid = (L + R) >> 1;
    	if (r <= mid) return query(lson, l, r);
    	else if (l > mid) return query(rson, l, r);
    	else return query(lson, l, mid) + query(rson, mid + 1, r);
    }
    
    LL calc(int x){
    	return query(1, 1, n, f[x], f[x] + sz[x] - 1);
    }
    
    LL work(int x, LL val){
    	update(1, 1, n, f[x], f[x] + sz[x] - 1, val);
    }
    
    int calc_lca(int x, int y, int cnt){
    	return LCA(x, y) ^ LCA(x, cnt) ^ LCA(y, cnt);
    }
    
    
    int main(){
    
    	scanf("%d%d", &n, &m);
    	rep(i, 1, n) scanf("%lld", a + i);
    
    	ti = 0;
    	rep(i, 2, n){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    
    	dfs1(1, 0, 0);
    	dfs2(1, 1);
    
    	build(1, 1, n);
    
    	cnt = 1;
    
    	int ca = 0;
    	while (m--){
    		int op;
    		scanf("%d", &op);
    
    		if (op == 3){
    			int x;
    			scanf("%d", &x);
    			if (x == cnt){
    				printf("%lld
    ", calc(1));
    				continue;
    			}
    
    			int lca = LCA(x, cnt);
    			if (lca == x){
    				int y = twz(x, cnt);
    				printf("%lld
    ", calc(1) - calc(y));
    				continue;
    			}
    
    			printf("%lld
    ", calc(x));
    		}
    
    		else if (op == 1){
    			int x;
    			scanf("%d", &x);
    			cnt = x;
    		}
    
    		else{
    			int x, y;
    			LL val;
    			scanf("%d%d%lld", &x, &y, &val);
    
    			int z = calc_lca(x, y, cnt);
    			if (z == cnt){
    				work(1, val);
    				continue;
    			}
    
    			int lca = LCA(z, cnt);
    			if (lca == z){
    				int yy = twz(z, cnt);
    				work(1, val);
    				work(yy, -val);
    				continue;
    			}
    
    			work(z, val);			
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    ThinkPhp框架分页查询和部分框架知识
    tp框架增删改
    WAMP中mysql服务突然无法启动 解决方法
    thinkphp框架 的 链接数据库和操作数据
    php 全局使用laravel的dd和dump
    给centos装图形界面 widowsx
    marquee标签的使用
    微信公众号开发入门教程
    laravel admin引入css js报错 https
    利用Croppie裁剪图片并后台保存
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8433953.html
Copyright © 2020-2023  润新知