日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

牛客多校10 - Decrement on the Tree(边权转点权+思维)

發布時間:2024/4/11 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 牛客多校10 - Decrement on the Tree(边权转点权+思维) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一棵 n 個點組成的樹,每條邊上都有邊權,現在可以進行數次操作,每次操作可以選擇一條路徑,使得路徑上的權值減一,問最少需要進行多少次操作才能使得所有的邊權變為 0 ,輸出這個操作次數,再給出 m 次詢問,每次詢問會修改一條邊權,每次需要回答修改邊權后的答案

題目分析:讀完題的第一感覺是樹形dp然后用樹剖+線段樹優化,事實證明確實可以寫,但我不會寫

講一下官方題解的做法吧,非常需要思維,首先需要將邊權轉換為點權,對于每次操作選取一條路徑然后將其路徑上的邊權減一,對應過來就是將兩個端點遍歷一次,這樣問題就轉換為了,將所有邊權變為 0 時,令每個端點被訪問的次數之和最小

對于每個點計算貢獻,就會發現有兩種情況:假設 mmax 為與當前點相連的所有邊中,權值最大的邊權,sum 為與當前點相連的所有邊權之和

  • mmax <=?( sum - mmax ):此時肯定有一種匹配方法使得邊權兩兩互相匹配,換句話說,當前點不需要作為端點與其他端點形成路徑,只需要作為中間點被經過就好,這樣的貢獻就是 sum%2 ,因為如果 sum 為奇數的話,會有一條邊權失配,那么只能由該點作為端點一次
  • mmax > ( sum - mmax ):此時如果其余所有的邊都與 mmax 匹配的話,最終還是會剩下 mmax - ( sum - mmax ) 的邊權失配,那么需要當前點作為端點這么多次才行
  • 對于每次修改,只需要維護一個 multiset 實時計算貢獻就好了

    最后的答案記得除以 2 ,因為當邊權映射給點權后,是一條邊權對應著兩個端點,我們維護的 ans 是最少點的貢獻,轉換為邊的貢獻當然應該除以 2 了

    代碼:
    ?

    #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;multiset<int>st[N];LL sum[N];int x[N],y[N],w[N];void del(int p) {int x=::x[p],y=::y[p],w=::w[p];st[x].erase(st[x].find(w));st[y].erase(st[y].find(w));sum[x]-=w;sum[y]-=w; }void add(int p) {int x=::x[p],y=::y[p],w=::w[p];st[x].insert(w);st[y].insert(w);sum[x]+=w;sum[y]+=w; }LL cal(int p) {int mmax=*st[p].rbegin();if(mmax*2>sum[p])return mmax*2-sum[p];elsereturn sum[p]&1; }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m;scanf("%d%d",&n,&m);for(int i=1;i<n;i++){scanf("%d%d%d",x+i,y+i,w+i);add(i);}LL ans=0;for(int i=1;i<=n;i++)ans+=cal(i);printf("%lld\n",ans/2);while(m--){int pos,val;scanf("%d%d",&pos,&val);ans-=cal(x[pos])+cal(y[pos]);del(pos);w[pos]=val;add(pos);ans+=cal(x[pos])+cal(y[pos]);printf("%lld\n",ans/2);}return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的牛客多校10 - Decrement on the Tree(边权转点权+思维)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。