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\n", calc(1));
				continue;
			}

			int lca = LCA(x, cnt);
			if (lca == x){
				int y = twz(x, cnt);
				printf("%lld\n", calc(1) - calc(y));
				continue;
			}

			printf("%lld\n", 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;
}

 

posted @ 2018-02-09 00:33  cxhscst2  阅读(246)  评论(0编辑  收藏  举报