AtCoder Beginner Contest 187 E - Through Path
题目链接
https://atcoder.jp/contests/abc187/tasks/abc187_e
题意
给你一棵\(n\)个节点的树,一开始节点权值都为\(0\),\(N-1\)条边,每条边连接\(a[i] - b[i]\),俩种操作:
1.以\(a[i]\)为起点遍历所有的点且路径上不能经过\(b[i]\),路径上的所有点加\(w\).
2.以\(b[i]\)为起点遍历所有的点且路径上不能经过\(a[i]\),路径上的所有点加\(w\).
问最终每个点的权值.
思路
仔细研究会发现其实每次操作就是选一条边把树拆成左右俩个部分,然后\(2\)种操作分别对应左边还是右边的所有点加上权值\(w\)。
那么我们可以任意节点为根,求出每个点的深度,对于每次操作,根据\(a[i]和b[i]\)的远近来给部分加权。
给部分加权 = 给子树加权可以转化为DFS序列,对于某个部分不是某个点的子树(另一半肯定是某个点的子树),可以给另一部分减权,再给全部点加权。
(加权我用了很傻很暴力的线段树, 其实差分就好了)
AC代码
#include<bits/stdc++.h>
#define ls rt << 1
#define rs rt << 1 | 1
#define lson l , mid , rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define lr2 (l + r) >> 1
using namespace std;
typedef long long ll;
const int maxn = 4e5 + 50;
ll sum[maxn << 2], lazy[maxn << 2];
int L[maxn], R[maxn];
void push_up(int rt){
sum[rt] = sum[ls] + sum[rs];
}
void push_down(int rt, int m){
if(lazy[rt])
{
lazy[ls] += lazy[rt];
lazy[rs] += lazy[rt];
sum[ls] += lazy[rt] * (m - (m >> 1));
sum[rs] += lazy[rt] * (m >> 1);
lazy[rt] = 0;
}
}
void update(int a, int b, ll v, int l, int r, int rt){
if(a <= l && b >= r){
sum[rt] += 1LL * (r - l + 1) * v;
lazy[rt] += v;
return;
}
push_down(rt, r - l + 1);
int mid = lr2;
if(a <= mid) update(a, b, v, lson);
if(b > mid) update(a, b, v, rson);
push_up(rt);
}
ll query(int a, int b, int l, int r, int rt){
if(a <= l && b >= r){
return sum[rt];
}
int mid = lr2;
push_down(rt, r - l + 1);
ll ans = 0;
if(a <= mid) ans += query(a, b, lson);
if(b > mid) ans += query(a, b, rson);
return ans;
push_up(rt);
}
int a[maxn], b[maxn];
int cnt, n;
vector<int> G[maxn];
int d[maxn];
void dfs(int v, int fa){
L[v] = ++cnt;
d[v] = d[fa] + 1;
for(auto u : G[v]){
if(u != fa){
dfs(u, v);
}
}
R[v] = cnt;
}
int main()
{
std::ios::sync_with_stdio(false);
cin >> n;
for(int i = 1;i < n;i++){
cin >> a[i] >> b[i];
G[a[i]].push_back(b[i]);
G[b[i]].push_back(a[i]);
}
dfs(1, 0);
int q;
cin >> q;
ll ans = 0;
while(q--){
int t, id;
ll x;
cin >> t >> id >> x;
if(t == 1){
if(d[a[id]] < d[b[id]]){
ans += x;
update(L[b[id]], R[b[id]], -x, 1, n, 1);
}
else update(L[a[id]], R[a[id]], x, 1, n, 1);
}
else{
if(d[b[id]] < d[a[id]]){
ans += x;
update(L[a[id]], R[a[id]], -x, 1, n, 1);
}
else update(L[b[id]], R[b[id]], x, 1, n, 1);
}
}
for(int i = 1;i <= n;i++) cout << query(L[i], L[i], 1, n ,1) + ans << endl;
return 0;
}