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;
}
Code will change the world !

浙公网安备 33010602011771号