CF 1076E Vasya and a Tree(dfs+树状数组)

链接:http://codeforces.com/problemset/problem/1076/E

 

题意:给你一颗以1为根节点的树,初始所有节点的权值为0,然后有m个操作,每个操作将点v的儿子节点中和本身的所有距离不超过d的节点权值加x,问经过m次操作后,输出每个节点的权值。

题解:如果是一个序列,就可以直接用树状数组做,但这是一颗树,所以我们可以想办法把它转化成序列。我们可以先求出每个节点的dfs序,以及深度和子树的大小,顺便记录每个深度都有哪些节点,子树的大小用来确认以该节点为根的子树在dfs序中的范围,此时便可用树状数组维护了。之后,我们把每个操作按能影响到的深度从大到小排序,即优先处理影响深度大的操作。设当前计算的深度为now,假设所有操的作影响的深度大于now的操作已经计算。如果当前操作影响的深度小于now,说明所有能影响到now深度的操作已经全部操作完了,此时把所有深度为now的节点权值计算出来。每读取一个操作的信息,就把操作产生的影响用树状数组维护,因为影响now深度的节点权值已经计算完毕了,所以我把以该操作的操作节点为根的子树全部加上操作的值 对之前已经计算的答案没有影响。操作全部完成后,深度从深到浅计算答案即可。

 

代码:

#include <bits/stdc++.h>
#define IO_read ios::sync_with_stdio(false);cin.tie(0)
#define fre freopen("in.txt", "r", stdin)
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
using namespace std;
typedef long long ll;
#define lowbit(a) ((a)&-(a))

const int maxn=3e5+5;

int tot, head[maxn*2];
struct Edge{
    int to, next;
}edge[maxn*2];

void addedge(int u, int v)
{
    edge[++tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}

int n, m;
int deep[maxn], dfsn[maxn], sz[maxn];
int max_deep, cnt_dfs;
vector<int> vec[maxn];

void dfs(int u, int now_deep)
{
    max_deep=max(max_deep, now_deep);
    sz[u]=1, deep[u]=now_deep, dfsn[u]=++cnt_dfs;
    vec[now_deep].push_back(u);
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if(dfsn[v]) continue;  //连了2次边,要判断
        dfs(v, now_deep+1);
        sz[u]=sz[u]+sz[v];
    }
}

struct Opt{
    int rt, d, x;
    bool operator <(const Opt &a)const{
        return deep[rt]+d>deep[a.rt]+a.d;
    }
}opt[maxn];

ll tree[maxn], ans[maxn];

void add(int x, int val)
{
    for(int i=x; i<=n; i+=lowbit(i))
        tree[i]+=val;
}

ll ask(int x)
{
    ll res=0;
    for(int i=x; i; i-=lowbit(i))
        res+=tree[i];
    return res;
}

int main()
{
    IO_read;
    //fre;
    memset(head, -1, sizeof(head));
    cin>>n;
    _rep(i, 1, n-1)
    {
        int u, v;
        cin>>u>>v;
        addedge(u, v);
        addedge(v, u);
    }
    
    cin>>m;
    _rep(i, 1, m)
        cin>>opt[i].rt>>opt[i].d>>opt[i].x;
    dfs(1, 1);  //注意后面的排序用到了deep数组,所以要先dfs,在排序
    sort(opt+1, opt+1+m);
    
    int now_deep=max_deep;
    _rep(i, 1, m)
    {
        int rt=opt[i].rt, d=opt[i].d, x=opt[i].x;
        while(deep[rt]+d<now_deep)
        {
            for(int j=0; j<vec[now_deep].size(); j++)
            {
                int v=vec[now_deep][j];
                ans[v]=ask(dfsn[v]);
            }
            now_deep--;
        }
        add(dfsn[rt], x);
        add(dfsn[rt]+sz[rt], -x);
    }
    while(now_deep)  //注意这样写deep从1开始
    {
        for(int j=0; j<vec[now_deep].size(); j++)
        {
            int v=vec[now_deep][j];
            ans[v]=ask(dfsn[v]);
        }
        now_deep--;
    }
    _rep(i, 1, n)
        cout<<ans[i]<<" ";
    return 0;
}

 

posted @ 2019-10-22 17:02  N_Yokel  阅读(138)  评论(0编辑  收藏  举报