• [CF1076E] Vasya and a Tree


    题意

    Here

    思考

    简要题意就是给定多个操作,每次操作将(u) 距离小于等于 (k) 且在 (u) 子树内的点点权值加 (x) ,输出最终各个点的权值。

    看这题的时候我先想的是树剖,发现树剖并不好处理两点的距离限制

    第二种想法是 (bfs) 序,想想可能不好处理(不考虑超时的话可以做,线段树维护 (bfs) 序,对于每一层我们知道节点编号的区间,然后每一层二分区间左右端点来判断是否在 (u) 的子树内,再更新,时间复杂度有、爆炸)

    于是当时这题成功地没有做出来,我过于菜

    考完看了看别人的代码...发现自己智障了...

    考虑单独的一个节点 (u),它的操作影响的都是在它子树内的与 (u) 深度差小于等于 (k) 的节点,那么我们只要维护当前深度操作总和就行了(树状数组或线段树),但有一个问题,由于 (u) 点的操作只影响 (u) 的子树,其他节点怎么办 ? 我们可以先将所有操作离线,再总体按 (dfs) 实现:

    1. 进入该点
    2. 实现该点的所有操作
    3. 递归它的子树
    4. 撤销操作

    这样 (u) 的操作就不会影响到其他子树上的点了,还有一个好处,我们并不需要修改深度 (dep(u))~(dep(u)+k) 而只需修改 (dep(k)) 最后查询的时候查 (sum(dep(u))~(sum(max)))就好,因为当查询到这个点时,只有 (u) 的祖先节点的操作实现了,那么对于任意的 (u) 的儿子节点,如果它的值有修改,说明这个修改操作是来自 (u) 的祖先节点的,所以 (u) 肯定也会被修改

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x * f;
    }
    const ll N = 300030;
    struct node{
        ll nxt, to;
    }edge[N << 1];
    ll head[N], num;
    void build(ll from, ll to){
        edge[++num].nxt = head[from];
        edge[num].to = to;
        head[from] = num;
    }
    ll c[N], n, m;
    ll lowbit(ll x){ return x & -x; }
    void add(ll pos, ll v){
        for(ll i=pos; i<=n; i+=lowbit(i)) c[i] += v;
    }
    ll query(ll pos){
        ll ans = 0;
        for(ll i=pos; i; i-=lowbit(i)) ans += c[i];
        return ans;
    }
    vector<ll> val[N], D[N];
    ll ans[N];
    void dfs(ll u, ll f, ll d){
        for(ll i=0; i<D[u].size(); i++){
            add(min(n, D[u][i] + d), val[u][i]);
        }
        ans[u] = query(n) - query(d - 1);
        for(ll i=head[u]; i; i=edge[i].nxt){
            ll v = edge[i].to;
            if(v == f) continue;
            dfs(v, u, d + 1);
        }
        for(ll i=0; i<D[u].size(); i++){
            add(min(n, D[u][i] + d), -val[u][i]);
        }
    }
    int main(){
        n = read();
        for(ll i=1; i<=n-1; i++){
            ll u = read(), v = read();
            build(u, v); build(v, u);
        }
        m = read();
        for(ll i=1; i<=m; i++){
            ll u = read(), d = read(), v = read();
            D[u].push_back(d);
            val[u].push_back(v);
        }
        dfs(1, 0, 1);
        for(ll i=1; i<=n; i++){
            cout << ans[i] << " ";
        }
        return 0;
    }
    
    

    总结

    注意题目性质,树上的技巧要多学习……

  • 相关阅读:
    Slf4j与log4j及log4j2、logbak的关系及使用方法
    Swagger
    C#解析json的两种方式
    akka java
    JAVA协程 纤程 与Quasar 框架
    Java 终于在 Java 8 中引入了 Lambda 表达式。也称之为闭包或者匿名函数。
    Deep Learning(深度学习)相关网站
    Deep Learning(深度学习)学习笔记整理系列之(八)
    Deep Learning(深度学习)学习笔记整理系列之(七)
    Deep Learning(深度学习)学习笔记整理系列之(六)
  • 原文地址:https://www.cnblogs.com/alecli/p/9971695.html
Copyright © 2020-2023  润新知