AtCoder Beginner Contest 187 E - Through Path
阿新 • • 發佈:2021-01-09
題目連結
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; }