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;
}

原文地址:https://www.cnblogs.com/Carered/p/14255797.html