2021杭电多校第二场 1002——I love tree

这篇博客介绍了如何利用树链剖分和线段树来处理树上的一种操作:对从节点u到节点v路径上的节点按照与u的距离平方加权更新值,并能快速查询节点x的值。博主详细阐述了算法的思路,包括树链剖分、线段树的建立和维护,以及如何进行操作1和查询操作2。
摘要由CSDN通过智能技术生成

题目大意

给你一棵树,有两种操作
1、将路径 u u u v v v 上的点按照与 u u u 的距离,加上 1   4   9 ⋯ i 2 1 \ 4 \ 9 \cdots i^2 1 4 9i2
2、问节点 x x x 的值为多少

解题思路

树链剖分 + 线段树
首先我们可以进行一个树链剖分,这样便于处理操作1。
对于操作1,我们首先找出 u u u v v v l c a lca lca
对于树链 u u u l c a lca lca,我们每个节点所加的值为
( d e p [ t ] − d e p [ u ] + 1 ) 2 (dep[t] - dep[u] + 1)^2 (dep[t]dep[u]+1)2
化简一下
d e p [ t ] 2 − 2 × ( d e p [ u ] − 1 ) × d e p [ t ] + ( d e p [ u ] − 1 ) 2 dep[t]^2 - 2\times (dep[u] - 1) \times dep[t] + (dep[u] - 1)^2 dep[t]22×(dep[u]1)×dep[t]+(dep[u]1)2
我们可以开三个线段树维护这三个值,我们发现,对于每个点的 d e p [ t ] dep[t] dep[t] 是确定的,所以我们只需要记录一下这个多项式的系数即可。
对于树链 v v v l c a lca lca,每个节点所加的值为
( d e p [ t ] − ( 2 × d e p [ l c a ] − d e p [ x ] − 1 ) ) 2 (dep[t] - (2\times dep[lca] - dep[x] - 1))^2 (dep[t](2×dep[lca]dep[x]1))2
化简一下
d e p [ t ] 2 − 2 × ( 2 × d e p [ l c a ] − d e p [ x ] − 1 ) × d e p [ t ] + ( 2 × d e p [ l c a ] − d e p [ x ] − 1 ) 2 dep[t]^2 - 2\times (2\times dep[lca] - dep[x] - 1) \times dep[t] + (2\times dep[lca] - dep[x] - 1)^2 dep[t]22×(2×dep[lca]dep[x]1)×dep[t]+(2×dep[lca]dep[x]1)2

Code

#include <bits/stdc++.h>
#define ll long long
#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 MAXN = 2e5 + 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 n, m;
int fa[MAXN], sz[MAXN], top[MAXN], dfn[MAXN], son[MAXN], dep[MAXN];
int tim;
struct Tree{
	struct T{
		int l, r;
		ll sum, add;
	}tree[MAXN << 2];
	void pushup(int rt){
		tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
	}
	void build(int l, int r, int rt){
		tree[rt].l = l;
		tree[rt].r = r;
		tree[rt].add = 0;
		tree[rt].sum = 0;
		if(l == r) return ;
		int m = (l + r) >> 1;
		build(l, m, rt << 1);
		build(m+1, r, rt << 1 | 1);
	}
	void pushdown(int rt){
		if(tree[rt].add){
			tree[rt << 1].add += tree[rt].add;
			tree[rt << 1].sum += (tree[rt << 1].r - tree[rt << 1].l + 1) * tree[rt].add;
			tree[rt << 1 | 1].add += tree[rt].add;
			tree[rt << 1 | 1].sum += (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) * tree[rt].add;
			tree[rt].add = 0;
		}
	}
	ll query(int L, int R, int rt){
		if(L <= tree[rt].l && tree[rt].r <= R)
			return tree[rt].sum;
		pushdown(rt);
		int m = (tree[rt].l + tree[rt].r) >> 1;
		ll ret = 0;
		if(L <= m)
			ret += query(L, R, rt << 1);
		if(m < R)
			ret += query(L, R, rt << 1 | 1);
		return ret;
	}
	void update(int L, int R, ll x, int rt){
		if(L <= tree[rt].l && tree[rt].r <= R){
			tree[rt].sum += (tree[rt].r - tree[rt].l + 1) * x;
			tree[rt].add += x;
			return ;
		}
		pushdown(rt);
		int m = (tree[rt].l + tree[rt].r) >> 1;
		if(L <= m)
			update(L, R, x, rt << 1);
		if(m < R)
			update(L, R, x, rt << 1 | 1);
		pushup(rt);
	}
}tree[3];
int head[MAXN];
struct edge{
	int to, next;
}e[MAXN << 1];
int tot;
void init(){
	memset(head, -1, sizeof(head));
	tot = 0;
}
void add(int u, int v){
	e[tot].to = v;
	e[tot].next = head[u];
	head[u] = tot++;
}
void dfs1(int x, int f){
	dep[x] = dep[f] + 1;
	sz[x] = 1;
	fa[x] = f;
	int maxx = 0;
	for(int i = head[x]; ~i; i = e[i].next){
		int v = e[i].to;
		if(v == f) continue;
		dfs1(v, x);
		sz[x] += sz[v];
		if(sz[v] > maxx){
			maxx = sz[v];
			son[x] = v;
		}
	}
}
void dfs2(int u, int t ){
	top[u] = t;
	dfn[u] = ++tim;
	if(!son[u]) return;
	dfs2(son[u], t);
	for(int i = head[u]; ~i; i = e[i].next){
		int v = e[i].to;
		if(v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}
int LCA(int x, int y){
	while(top[x] != top[y]){
		if(dep[top[x]] > dep[top[y]]) swap(x, y);
		y = top[y];
		y = fa[y];
	}
	return dep[x] > dep[y] ? y : x;
}
void slove(int x, int y){
	int lca = LCA(x, y);
	ll p = dep[x] + 1;
	int xx = x;
	while(top[x] != top[lca]){
		tree[0].update(dfn[top[x]], dfn[x], 1, 1);
		tree[1].update(dfn[top[x]], dfn[x], -2*p, 1);
		tree[2].update(dfn[top[x]], dfn[x], p*p, 1);
		x = fa[top[x]];
	}
	tree[0].update(dfn[lca], dfn[x], 1, 1);
	tree[1].update(dfn[lca], dfn[x], -2*p, 1);
	tree[2].update(dfn[lca], dfn[x], p*p, 1);
	tree[0].update(dfn[lca], dfn[lca], -1, 1);
	tree[1].update(dfn[lca], dfn[lca], 2*p, 1);
	tree[2].update(dfn[lca], dfn[lca], -p*p, 1);
	p = 2*dep[lca] - dep[xx] - 1;
	while(top[y] != top[lca]){
		tree[0].update(dfn[top[y]], dfn[y], 1, 1);
		tree[1].update(dfn[top[y]], dfn[y], -2*p, 1);
		tree[2].update(dfn[top[y]], dfn[y], p*p, 1);
		y = fa[top[y]];
	}
	tree[0].update(dfn[lca], dfn[y], 1, 1);
	tree[1].update(dfn[lca], dfn[y], -2*p, 1);
	tree[2].update(dfn[lca], dfn[y], p*p, 1);
}
ll query(int x){
	return dep[x] * dep[x] * tree[0].query(dfn[x], dfn[x], 1) +  dep[x] * tree[1].query(dfn[x], dfn[x], 1) + tree[2].query(dfn[x], dfn[x], 1);
}
void solve(){
	init(); 
	cin >> n;
	for (int i = 1; i <= n-1; ++i){
	    int u, v;
		cin >> u >> v;
		add(u, v);
		add(v, u);
	}
	dfs1(1, 1);
	dfs2(1, 1);
	for (int i = 0; i <= 2; ++i){
		tree[i].build(1, n, 1);
	}
	int q;
	cin >> q;
	while(q--){
		int op;
		cin >> op;
		if(op == 1){
			int u, v;
			cin >> u >> v;
			slove(u, v);
		}
		else{
			int x;
			cin >> x;
			cout << query(x) << "\n";
		}
	}
}

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

    qc;
    int T;
    // cin >> T;
    T = 1;
    while(T--){

        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值