• cf 1076e 树上差分+树状数组+离线


    http://codeforces.com/contest/1076/problem/E

    参考博客:http://www.cnblogs.com/AKMer/p/9950332.html

    题意:

    根节点为1 树,m次操作,每次给定v,d,x,将v的儿子(包含其本身)与它距离<=d的权值加上x

    问最后 所有节点的权值

    思路:

    离线操作

    将m次操作保存,之后在dfs的时候用树状数组动态维护深度差分值

    ,然后单点询问当前深度应该增加多少就行了。如果本子树处理完了,那么就把差分去掉,以免影响其它子树。

    注意:因为树状数组是以深度为基础的,所以对一个子树,其深度符合条件,就可以加上

         然后这个子树访问完毕,在用树状数组反差分回去


    开始数组忘了*2     居然给mle而不是re....

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define low(i) ((i)&(-i))
    const int N = 3e5+3;
    
    int dep[N];int n;
    ll ans[N];
    vector<  pair<int,int >  >qu[N];
    vector< pair<int,int > >::iterator it;
    int y[N*2],fst[N],nxt[N*2];
    int cnt;
    void addedge(int a,int b){
        y[++cnt] =b;
        nxt[cnt] = fst[a];
        fst[a] = cnt;
    }
    struct TreeArray {
        ll c[N];
        void add(int pos,int v) {
            for(int i=pos;i<=n;i+=low(i))
                c[i]+=v;
        }
        ll query(int pos) {
            ll res=0;
            for(int i=pos;i;i-=low(i))
                res+=c[i];
            return res;
        }
    }T;
    
    
    void dfs(int x,int pre){
        dep[x] =dep[pre]+1;
        for(int i=fst[x];i;i=nxt[i]){
            if(y[i]!=pre)
                dfs(y[i],x);
        }
    }
    
    void get(int pre,int x){
        ////进来的时候差分
        for( it = qu[x].begin();it!=qu[x].end();++it){
            T.add(dep[x],(*it).se);
            //这里 是 r+1
            T.add(  min(n,dep[x]+(*it).fi)+1,-(*it).se);
        }
    
        ans[x] = T.query(dep[x]);
        for(int i=fst[x];i;i=nxt[i]){
            if(y[i]!=pre)get(x,y[i]);
        }
        //出去的时候反差分
        for( it = qu[x].begin();it!=qu[x].end();++it){
            T.add(dep[x],-(*it).se);
            //这里 是 r+1
            T.add(  min(n,dep[x]+ (*it).fi)+1,(*it).se);
        }
    }
    
    int main(){
        scanf("%d",&n);
        int v,u,m,d,x;
        for(int i=1;i<n;++i){
            scanf("%d %d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
    
        dfs(1,0);
    
        scanf("%d",&m);
        while(m--){
            scanf("%d %d %d",&v,&d,&x);
            qu[v].push_back(  mp(d,x));
        }
    
        get(0,1);
    
        for(int i=1;i<=n;++i)
            printf("%lld ",ans[i]);
    
        return 0;
    }
  • 相关阅读:
    [na]ip数据包格式
    [js]浏览器同源策略(same-origin policy)
    [sql] 同库表(结构)的备份和sql聚合&navicat使用
    [svc]tcp三次握手四次挥手&tcp的11种状态(半连接)&tcp的time-wait
    [svc]ip地址划分
    [css]单/多行居中&字体设置
    时间戳转为C#格式时间
    windows 8 中 使用 httpclient
    oralce 查看是否启动 登陆 创建用户 常用命令小记
    SQL递归查询(with cte as)
  • 原文地址:https://www.cnblogs.com/wjhstudy/p/9991482.html
Copyright © 2020-2023  润新知