zoukankan      html  css  js  c++  java
  • 2020牛客多校第十场C-Decrement on the Tree

    https://ac.nowcoder.com/acm/contest/5675/C

    题意

    给出一个树,q次修改,每次修改将第p条边权值修改为w。

    回答q+1询问,每次操作可以选择一条链,把这条链上所有边的权值减一,问最少进行多少次操作才能把所有边权全部归零。

    题解

    考虑每个节点的边进行匹配,如果最大边权值大于了剩下所有边的权值和,那么剩下所有边和它匹配也无法把这条边的权值匹配完,则会产生(mx-(sum[u]-mx)=2*mx-sum[u])的贡献,否则,如果边权和为偶数,则一定能两两匹配,也就是子树中不存在路径的起讫点,如果为奇数,则存在一个起点,答案+1。

    思考到这里这道题就很简单了,用一个set维护一下边权的大小关系,修改时只需要计算相关影响的点对答案的影响即可,注意由于每个点都考虑一遍,所有的边被考虑了两遍,ans/=2

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct READ {
        inline char read() {
        #ifdef _WIN32
            return getchar();
        #endif
            static const int IN_LEN = 1 << 18 | 1;
            static char buf[IN_LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            static char c11, boo;
            for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
                if(c11 == -1) return *this;
                boo |= c11 == '-';
            }
            for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
            boo && (x = -x);
            return *this;
        }
    } in;
    
    const int N = 1e5 + 50;
    struct node {
        int u, v, w;
    } edge[N];
    multiset<int> st[N];
    ll sum[N];
    ll ans = 0;
    int calc(int u) {
        int mx = *(--st[u].end());
        if (2ll * mx >= sum[u]) return 2 * mx - sum[u];
        else return sum[u] & 1;
    }
    void update(int p, int w) {
        int u = edge[p].u, v = edge[p].v;
        ans -= calc(u); ans -= calc(v);
        sum[u] += w - edge[p].w; sum[v] += w - edge[p].w;
        st[u].erase(st[u].lower_bound(edge[p].w)); st[u].insert(w);
        st[v].erase(st[v].lower_bound(edge[p].w)); st[v].insert(w);
        ans += calc(u); ans += calc(v);
        edge[p].w = w;
    }
    int main() {
        int n, q; in >> n >> q;
        for (int i = 1; i < n; i++) {
            int u, v, w; in >> u >> v >> w;
            edge[i] = {u, v, w};
            sum[u] += w; sum[v] += w;
            st[u].insert(w); st[v].insert(w);
        }
        
        for (int i = 1; i <= n; i++) ans += calc(i);
        printf("%lld
    ", ans / 2);
        while (q--) {
            int p, w; in >> p >> w;
            update(p, w);
            printf("%lld
    ", ans / 2);
        }
        return 0;
    }
    
  • 相关阅读:
    dotnet Framework 源代码 类库的意思
    dotnet Framework 源代码 类库的意思
    dotnet Framework 源代码 · Ink
    dotnet Framework 源代码 · Ink
    dotnet core 用值初始化整个数组
    dotnet core 用值初始化整个数组
    dotnet core 隐藏控制台
    dotnet core 隐藏控制台
    PHP mt_rand() 函数
    PHP mt_getrandmax() 函数
  • 原文地址:https://www.cnblogs.com/artoriax/p/13648875.html
Copyright © 2011-2022 走看看