牛客第十場自閉
阿新 • • 發佈:2020-08-12
C-Decrement on the Tree
統計每個點連線邊的邊權和以及最大邊權,然後進行如下貪心:
ll find(ll x)//將邊權存到了multiset<ll>s[x]
{
ll Max = *(--s[x].end());//x節點連的最大邊
if (Max >= sum[x] - Max)
return 2 * Max - sum[x];
return sum[x] % 2;
}
這樣找到的ans是比答案大1倍的,因為每一條邊連向了兩個點,那麼每一條邊都被統計了2次答案,所以ans最後還要/=2
寫了詳細註釋:
#include<bits/stdc++.h> using namespace std; #define ll long long #define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL) const int maxn = 1e5 + 10; const ll inf = 1e17; ll mod = 998244353; multiset<ll>s[maxn]; ll a[maxn], b[maxn], w[maxn], sum[maxn]; ll find(ll x) { ll Max = *(--s[x].end());//x節點連的最大邊 //cout << x << " " << Max << endl;; if (Max >= sum[x] - Max) return 2 * Max - sum[x]; return sum[x] % 2; } int main() { fastio; int n, q; cin >> n >> q; for (int i = 1; i < n; i++) { cin >> a[i] >> b[i] >> w[i];//由於q是按邊的序號修改的,那就得按序號存邊 sum[a[i]] += w[i], sum[b[i]] += w[i];//統計每個點的邊權和 s[a[i]].insert(w[i]);//將邊權插入每個點對應的multiset s[b[i]].insert(w[i]); } ll ans = 0; for (int i = 1; i <= n; i++) { ans += find(i);//統計答案 //cout << ans << endl; } cout << ans / 2 << endl;//每個邊被統計了2次,所以/=2 while (q--) { ll x, y; cin >> x >> y;//修改就是把對應的邊還原回來,然後改成需要的邊權,再統計一下這兩點的答案 ans -= find(a[x]) + find(b[x]); s[a[x]].erase(s[a[x]].find(w[x])); s[b[x]].erase(s[b[x]].find(w[x])); sum[a[x]] -= w[x] - y; sum[b[x]] -= w[x] - y; w[x] = y; s[a[x]].insert(y); s[b[x]].insert(y); ans += find(a[x]) + find(b[x]); cout << ans / 2 << endl; } return 0; }