• AtCoder Beginner Contest 187 E


    题目链接

    https://atcoder.jp/contests/abc187/tasks/abc187_e


    题意

    给你一棵(n)个节点的树,一开始节点权值都为(0)(N-1)条边,每条边连接(a[i] - b[i]),俩种操作:
    1.以(a[i])为起点遍历所有的点且路径上不能经过(b[i]),路径上的所有点加(w).
    2.以(b[i])为起点遍历所有的点且路径上不能经过(a[i]),路径上的所有点加(w).
    问最终每个点的权值.

    思路

    仔细研究会发现其实每次操作就是选一条边把树拆成左右俩个部分,然后(2)种操作分别对应左边还是右边的所有点加上权值(w)
    那么我们可以任意节点为根,求出每个点的深度,对于每次操作,根据(a[i]和b[i])的远近来给部分加权。
    给部分加权 = 给子树加权可以转化为DFS序列,对于某个部分不是某个点的子树(另一半肯定是某个点的子树),可以给另一部分减权,再给全部点加权。
    (加权我用了很傻很暴力的线段树, 其实差分就好了)

    AC代码

    #include<bits/stdc++.h>
    #define ls rt << 1
    #define rs rt << 1 | 1
    #define lson l , mid , rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    #define lr2 (l + r) >> 1
    using namespace std;
    typedef long long ll;
    const int maxn = 4e5 + 50;
    ll sum[maxn << 2], lazy[maxn << 2];
    int L[maxn], R[maxn];
    void push_up(int rt){
        sum[rt] = sum[ls] + sum[rs];
    }
    void push_down(int rt, int m){
        if(lazy[rt])
    	{
    		lazy[ls] += lazy[rt];
    		lazy[rs] += lazy[rt];
    		sum[ls] += lazy[rt] * (m - (m >> 1));
    		sum[rs] += lazy[rt] * (m >> 1);
    		lazy[rt] = 0;
    	}
    }
    void update(int a, int b, ll v, int l, int r, int rt){
        if(a <= l && b >= r){
            sum[rt] += 1LL * (r - l + 1) * v;
            lazy[rt] += v;
            return;
        }
        push_down(rt, r - l + 1);
        int mid = lr2;
        if(a <= mid) update(a, b, v, lson);
        if(b > mid) update(a, b, v, rson);
        push_up(rt);
    }
    ll query(int a, int b, int l, int r, int rt){
        if(a <= l && b >= r){
            return sum[rt];
        }
        int mid = lr2;
        push_down(rt, r - l + 1);
        ll ans = 0;
        if(a <= mid) ans += query(a, b, lson);
        if(b > mid) ans += query(a, b, rson);
        return ans;
        push_up(rt);
    }
    int a[maxn], b[maxn];
    int cnt, n;
    vector<int> G[maxn];
    int d[maxn];
    void dfs(int v, int fa){
        L[v] = ++cnt;
        d[v] = d[fa] + 1;
        for(auto u : G[v]){
            if(u != fa){
                dfs(u, v);
            }
        }
        R[v] = cnt;
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        cin >> n;
        for(int i = 1;i < n;i++){
            cin >> a[i] >> b[i];
            G[a[i]].push_back(b[i]);
            G[b[i]].push_back(a[i]);
        }
        dfs(1, 0);
        int q;
        cin >> q;
        ll ans = 0;
        while(q--){
            int t, id;
            ll x;
            cin >> t >> id >> x;
            if(t == 1){
                if(d[a[id]] < d[b[id]]){
                    ans += x;
                    update(L[b[id]], R[b[id]], -x, 1, n, 1);
                }
                else update(L[a[id]], R[a[id]], x, 1, n, 1);
            }
            else{
                if(d[b[id]] < d[a[id]]){
                    ans += x;
                    update(L[a[id]], R[a[id]], -x, 1, n, 1);
                }
                else update(L[b[id]], R[b[id]], x, 1, n, 1);
            }
        }
        for(int i = 1;i <= n;i++) cout << query(L[i], L[i], 1, n ,1) + ans << endl;
        return 0;
    }
    
    
  • 相关阅读:
    C#操作Windows控制面板
    WPF打印控件内容
    LINQ函数
    通过实现System.IComparable接口的CompareTo方法对两个类进行比较
    泛型和约束
    CSS样式基础总结
    C#调用百度高精度IP定位API通过IP获取地址
    软件下载路径
    RNN学习资料
    mysql 不能插入中文记录
  • 原文地址:https://www.cnblogs.com/Carered/p/14255797.html
Copyright © 2020-2023  润新知