题:https://ac.nowcoder.com/acm/contest/5675/C
题意:选择路径所有边权减1,问最少多少次操作能让所有边权等于0,支持边修改
分析:我们选择的路径只用考虑起点即可,对于一个节点我们用临边边权和来考量它;
第一种情况为有一条边的边权大于总和的一半,假设差值为x,那么必然有从此节点出发的路径x条
第二种情况为第一种情况没有发生,若总和为奇数,则必然有一条从此节点出发的路径,偶数则没有,因为一定会有由其他节点出发的路径经过它。
因此我们处理时只需要关注临边边权的最大值即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back #define pii pair<int,int> #define MP make_pair const int inf=0x3f3f3f3f; const int M=2e5+5; multiset<ll>g[M]; ll sum[M],w[M]; int x[M],y[M]; ll solve(int x){ multiset<ll>::iterator it=g[x].end(); it--; if(*it>sum[x]-*it)return 2*(*it)-sum[x]; return sum[x]&1; } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ scanf("%d%d%lld",&x[i],&y[i],&w[i]); g[x[i]].insert(w[i]); g[y[i]].insert(w[i]); sum[x[i]]+=w[i]; sum[y[i]]+=w[i]; } ll ans=0; for(int i=1;i<=n;i++) ans+=solve(i); printf("%lld\n",ans/2); while(m--){ int op; ll val; scanf("%d%lld",&op,&val); ans-=solve(x[op])+solve(y[op]); g[x[op]].erase(g[x[op]].find(w[op])); g[y[op]].erase(g[y[op]].find(w[op])); sum[x[op]]+=val-w[op]; sum[y[op]]+=val-w[op]; w[op]=val; g[x[op]].insert(w[op]); g[y[op]].insert(w[op]); ans+=solve(x[op])+solve(y[op]); printf("%lld\n",ans/2); } return 0; }
C Decrement on the Tree(选择路径所有边权减1,问多少次操作能让所有边权等于0)
原文:https://www.cnblogs.com/starve/p/13490236.html