zoukankan      html  css  js  c++  java
  • 2020暑假牛客多校10 C -Decrement on the Tree (边权转点权处理)

    C Decrement on the Tree

    参考博客

    题目:

    一棵树每次选择一条路径将路径上的边权都减1,问最少多少次操作后所有边权变成0。

    题解:

    看了好几篇博客才明白了,这道题的做法是将对边权的处理转变成去想对点的处理,算各点的贡献。之所以可以这样做是基于给一条边的边权-1,相当于访问这条边所连2个点各1次。

    如果不转换思路去考虑各边对结果的贡献,边的边权知道,两点知道,其他的如选的路径每次是什么都不清楚,所以会有一种思路很”窄“的感觉。但是换作考虑点的贡献,对每一个点,它连着好几条边。任意两个边都可以形成路径,将所有边减为0相当于这个点所连的边考虑边的权值关系下相互匹配,至于什么关系下面讨论,反正思路是很开阔的。这应该算是一种处理图问题的重要思路,当然有时候也把点的权值问题转为边的问题。

    讨论一个点各边权值关系的处理:

    (1) 最好想情况是 一个边权超级大,那么其他边都和这一边组成路径把其他边消为0,最后肯定这条边无法”蹭“别的路径去消除,只能自己消除,这就是当前点的贡献。设当前点为u, 其所连的总边权为sum , 超级大边权为maxx 。得该点贡献为:(sum-maxx是除maxx外其它边权和)

    [maxx - (sum - maxx) = 2*maxx-sum ]

    容易发现maxx >= sum / 2 时就属于情况(1) 。 感性理解就是其他边权和加起来都不能消除完maxx时是情况(1)

    (2) 如果maxx < sum / 2, 且u相连边总边权sum 为偶数时,肯定可以相互匹配完。贡献为0. sum为奇数时,最后一定会剩余1需要u作为贡献去处理掉。

    这样遍历一遍每个结点就可以求出中贡献,但是一个边对应2个点,所以算的结果应该除2才是对边得最少操作数。

    至于q次询问,每次O(1) 修改一下p边所连点得信息,重新算一下该边相连两点得贡献就可以算出答案。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, n) for(int i = a; i <= n; ++ i);
    #define per(i, a, n) for(int i = n; i >= a; -- i);
    typedef long long ll;
    const int N = 2e6+ 5;
    const int mod = 998244353;
    const double Pi = acos(- 1.0);
    const int INF = 0x3f3f3f3f;
    const int G = 3, Gi = 332748118;
    ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
    ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
    ll lcm(ll a, ll b) { return a * b / gcd(a, b);}
    bool cmp(int a, int b){ return a > b;}
    //
    
    int n, q; ll res;
    multiset<int> sol[N];
    int x[N], y[N];
    ll w[N], val[N];
    
    int cal(int i){	//计算每点贡献
        int tp = *sol[i].rbegin();
        if(2 * tp >= val[i]) return 2 * tp - val[i];
        else return val[i] & 1;
    }
    
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i = 1; i < n; ++ i){
            scanf("%d%d%lld",&x[i],&y[i],&w[i]);
            val[x[i]] += w[i], val[y[i]] += w[i];
            sol[x[i]].insert(w[i]); sol[y[i]].insert(w[i]);
        }
        for(int i = 1; i <= n; ++ i) res += cal(i);
        printf("%lld
    ",res / 2);
        
        while(q --){    //q次询问
            int p; ll tw; scanf("%d%lld",&p,&tw);
            res -= cal(x[p]) + cal(y[p]);
            val[x[p]] -= w[p]; val[y[p]] -= w[p];
            sol[x[p]].erase(sol[x[p]].find(w[p])); 
            sol[y[p]].erase(sol[y[p]].find(w[p]));
            
            w[p] = tw;
            val[x[p]] += tw; val[y[p]] += tw;
            sol[x[p]].insert(tw); sol[y[p]].insert(tw);
            res += cal(x[p]) + cal(y[p]);
            printf("%lld
    ",res / 2);
        }
        return 0;
    }
    
  • 相关阅读:
    VisualSVN-Server windows 版安装时报错 "Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details."
    Pytest 单元测试框架之初始化和清除环境
    Pytest 单元测试框架入门
    Python(email 邮件收发)
    Python(minidom 模块)
    Python(csv 模块)
    禅道简介
    2020年最好的WooCommerce主题
    Shopify网上开店教程(2020版)
    WooCommerce VS Magento 2020:哪个跨境电商自建站软件更好?
  • 原文地址:https://www.cnblogs.com/A-sc/p/13502719.html
Copyright © 2011-2022 走看看