I love tree——杭电第2场 1002

I love tree

HDU6962

题目描述

给出一棵树,树上点的初始权值为0,完成两个操作

  • 第一个操作,给出两个点 \(x,y\),将从\(x\)\(y\)路径上的点按顺序编号(从\(1\)开始),并将其权值加上对应编号的平方,如 \(x\)\(y\)的路径为\((x - x_1 - x_2 - y)\),则 \(f(x) += 1^2\), \(f(x_1) += 2^2\) \(f(x_2) += 3^2\) \(f(y) += 4^2\)。(\(f(x)\)表示x点的权值)
  • 第二个操作,给出点 \(x\),要求输出 \(x\)的权值。

解题思路

对于路径权值加上一个值,自然想到 树链剖分,但是这个题加上的权值不是定值,所以需要分析一下:
对于给定的两个点 \(u\)\(v\),因为是树链剖分,自然想到 \(lca\),因为树上两点间的路径是唯一的,并且一定经过它们的 \(lca\),所以可以分两部分看,

  • 对于 \(u - lca(u,v)\)这部分上的点 \(x\)来说,加上的值其实是 \((dep[u] - dep[x] + 1)^2\)\(dep[x]\)表示 \(x\)点的深度,对于这个式子,不难看出只有 \(x\)是变化的,所以我们令 \(y = dep[u] + 1\),则原式变为:\((dep[x] - y)^2 = (dep[x])^2 - 2*y*dep[x] + y^2\),因为对于每个 \(x\)来说 \(dep[x]\) 是已知的,所以我们只需要开三个线段树 \((T[0],T[1],T[2])\)维护这三个值即可,第一个线段树维护需要加几次 \((dep[x])^2\),第二个线段树维护系数 \(y\)的累加值,第三个线段树维护 \(y^2\)的累加值,最后 \(x\)点的权值就是 \(dep[x] * dep[x] * T[0].query(dfn[x],dfn[x],1) - 2 * dep[x] * T[1].query(dfn[x],dfn[x],1) + T[2].query(dfn[x],dfn[x],1)\)
  • 对于 \(lca(u,v) - v\) 的点 \(x\)道理同上,不过公示略有不同,此时加上的值应为 \(dep[u] - dep[lca(u,v)] +1 + dep[x] - dep[lca(u,v)]\),此时令 \(y = 2 * dep[lca(u,v)] - dep[u] - 1\)即可,其他同上。

不过需要注意的是处理 \(u - lca(u,v)\)这一段时,处理过了 \(lca(u,v)\),后面处理 \(lca(u,v) - v\)时也处理了 \(lca(u,v)\),所以 \(lca(u,v)\)处理了两次,故需要在处理完后减掉一次对 \(lca(u,v)\)的处理。

Code

#include <bits/stdc++.h>
#define ll long long
#define int long long
#define c(x,y) min(x,y),max(x,y)
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
using namespace std;
const int N = 2e6 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
//int a[N];
struct Segtree{
	struct TT{
		int l,r,sum,lazy;
	}tree[N<<2];
	//int j = 0;
	void pushup(int rt){
		tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
	}
	void pushdown(int rt){
		if(tree[rt].lazy != 0){
			tree[rt<<1].lazy += tree[rt].lazy;
			tree[rt<<1].sum += (tree[rt<<1].r - tree[rt<<1].l + 1) * tree[rt].lazy;
			tree[rt<<1|1].lazy += tree[rt].lazy;
			tree[rt<<1|1].sum += (tree[rt<<1|1].r - tree[rt<<1|1].l + 1) * tree[rt].lazy;
			tree[rt].lazy = 0;
		}
	}
	void build(int l,int r,int rt){
		tree[rt].l = l;
		tree[rt].r = r;
		tree[rt].sum = 0;
		tree[rt].lazy = 0;
		if(l == r){
			return;
		}
		int mid = (l+r) >> 1;
		build(l,mid,rt<<1);
		build(mid+1,r,rt<<1|1);
	}
	void update(int l,int r,int x,int rt){
		if(l <= tree[rt].l && tree[rt].r <= r){
			tree[rt].lazy += x;
			tree[rt].sum += (tree[rt].r - tree[rt].l + 1) * x;
			return;
		}
		pushdown(rt);
		int mid = (tree[rt].l + tree[rt].r) >> 1;
		if(l <= mid)
			update(l,r,x,rt<<1);
		if(mid < r)
			update(l,r,x,rt<<1|1);
		pushup(rt);
	}
	int query(int l,int r,int rt){
		if(l <= tree[rt].l && tree[rt].r <= r){
			return tree[rt].sum;
		}
		pushdown(rt);
		int mid = (tree[rt].l + tree[rt].r) >> 1;
		int res = 0;
		if(l <= mid)
			res += query(l,r,rt<<1);
		if(mid < r)
			res += query(l,r,rt<<1|1);
		return res;
	}
}T[3];
vector<int>v[N];
int dfn[N],fa[N],son[N],siz[N],top[N],tot,dep[N];
void dfs1(int x,int ff){
	dep[x] = dep[ff] + 1;
	fa[x] = ff;
	siz[x] = 1;
	int maxn = 0;
	for(int i : v[x]){
		if(i == ff)continue;
		dfs1(i,x);
		if(maxn < siz[i]){
			son[x] = i;
			maxn = siz[i];
		}
		siz[x] += siz[i];
	}
}
void dfs2(int x,int t){
	top[x] = t;
	dfn[x] = ++tot;
	if(son[x] > 0)dfs2(son[x],t);
	for(int i : v[x]){
		if(i == fa[x] || i == son[x])continue;
		dfs2(i,i);
	}
}
void slove(int x,int y){
	int xx = x,yy = y;
	while(top[x] != top[y]){
		if(dep[top[x]] > dep[top[y]])swap(x,y);
		y = top[y];
		y = fa[y];
	}
	if(dep[x] > dep[y])swap(x,y);
	int lca = x; //处理lca
	x = xx;
	y = yy;
	int p = dep[x] + 1;
	//对于x - lca 的点
	while(top[x] != top[lca]){
		T[2].update(c(dfn[x],dfn[top[x]]),p*p,1);
		T[1].update(c(dfn[x],dfn[top[x]]),p,1);
		T[0].update(c(dfn[x],dfn[top[x]]),1,1);
		x = top[x];
		x = fa[x];
	}
	T[2].update(c(dfn[x],dfn[lca]),p*p,1);
	T[1].update(c(dfn[x],dfn[lca]),p,1);
	T[0].update(c(dfn[x],dfn[lca]),1,1);
	T[2].update(dfn[lca],dfn[lca],-p*p,1);
	T[1].update(dfn[lca],dfn[lca],-p,1);
	T[0].update(dfn[lca],dfn[lca],-1,1);
	//对于lca - y 的点
	p = - dep[xx] + 2 * dep[lca] - 1;
	while(top[y] != top[lca]){
		T[2].update(c(dfn[y],dfn[top[y]]),p*p,1);
		T[1].update(c(dfn[y],dfn[top[y]]),p,1);
		T[0].update(c(dfn[y],dfn[top[y]]),1,1);
		y = top[y];
		y = fa[y];
	}
	T[2].update(c(dfn[y],dfn[lca]),p*p,1);
	T[1].update(c(dfn[y],dfn[lca]),p,1);
	T[0].update(c(dfn[y],dfn[lca]),1,1);
}
int query(int x){
	return dep[x] * dep[x] * T[0].query(dfn[x],dfn[x],1) - 2 * dep[x] * T[1].query(dfn[x],dfn[x],1) + T[2].query(dfn[x],dfn[x],1);
}
void solve(){
	int n;
	cin >> n;
	for(int i = 1; i < n; ++i){
		int x,y;
		cin >> x >> y;
		v[x].pb(y);
		v[y].pb(x);
	}
	dfs1(1,1);
	dfs2(1,1);
	for(int i = 0; i < 3; i++)T[i].build(1,n,1);
	int q;
	cin >> q;
	while(q--){
		int k;
		cin >> k;
		if(k == 1){
			int x,y;
			cin >> x >> y;
			slove(x,y);
		}else{
			int x;
			cin >> x;
			cout << query(x) << "\n";
		}
	}
}

signed main()
{
	#ifdef ONLINE_JUDGE
	#else
		freopen("in.txt", "r", stdin);
		freopen("out.txt", "w", stdout);
	#endif

	qc;
	int T = 1;
	while(T--){
		solve();
	}
	return 0;
}

posted @ 2021-08-24 18:15  !^^!  阅读(83)  评论(0)    收藏  举报