1. 程式人生 > 實用技巧 >AtCoder Beginner Contest 187 E - Through Path

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;
}