• Codeforces 1076E:Vasya and a Tree


    题意:给定一个n个点的树,初始每个点的点权都是0,接下来执行m次操作,每次操作在选择一个点u,将u的子树中距离u的距离(与u之间的边数)小于k的点的点权都加上d。

    最后询问每个点的点权。

    N,M<=3e5

    首先这里每次增加点权的点有些奇怪,因为并不一定是完整的一个子树(所以不能直接用DFS序转化成一条线段然后区间加),也不一定只是一条链(所以就不能树链剖分)。

    因为这道题并没有强制在线,只是要求输出所有操作执行完最后的结果,所以我们可以离线,然后改变执行询问的顺序。

    因为每次修改是发生在一个子树的内部的,所以一个合理的顺序是DFS序。

    我们把所有的修改都放到对应的点上,即子树修改的树根上。

    然后我们按照DFS序去遍历整棵树,顺便执行每次修改。

    在这个过程中,我们如何去处理每次的修改呢?

    注意到每次的修改其实是修改一个子树中深度在一定范围内的所有点,所有这些要被修改点权的点的性质就是在一个点的子树内,并且深度落在一个完整的区间内,所以我们应当想到去维护一个数组,记录每个深度的点的点权修改量。那么整个思路就出来了,当我们DFS进入一个点时,我们可以处理这个点上的所有修改,把这些贡献都加上,因为是区间加,所有我们可以用线段树或者树状数组来完成这件事。每个点的最终点权就是处理到这个点时,当前点深度的总修改量值。也就是单点查询。然后按照DFS的顺序去遍历每个孩子就OK了。离开这个点时,我们自然要把当前点的影响全部消去。(因为不在当前点子树内的点不会受到当前点的修改的影响)

    总体来说,做出这道题的关键就在于注意到每次询问被修改的点的深度是连续的,然后因为子树的限制,选择DFS序去顺便处理。进入一个子树时添加修改,离开一个子树时消除修改。

    复杂度O(N+MlogN)

    #include<bits/stdc++.h>
    #define lson(p) p<<1
    #define rson(p) p<<1|1
    using namespace std;
    const int maxn=3e5;
    typedef long long ll;
    vector<pair<int,int> > v[maxn+5];
    int dep[maxn+5];
    ll ans[maxn+5];
    int n,x,y,q,d,delta;
    struct edge
    {
        int to,_next;
    }G[2*maxn+5];
    int head[maxn+5];
    int num=0;
    void add(int u,int v)
    {
        G[++num].to=v;
        G[num]._next=head[u];
        head[u]=num;
    }
    struct SegmentTree
    {
        ll lazy;
        ll sum;
    }b[4*maxn+5];
    void build(int p,int l,int r)
    {
        b[p].lazy=0;
        if (l==r) {
            b[p].sum=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(lson(p),l,mid);
        build(rson(p),mid+1,r);
    }
    void pushdown(int p)
    {
        if (b[p].lazy) {
            b[lson(p)].sum+=b[p].lazy; b[rson(p)].sum+=b[p].lazy;
            b[lson(p)].lazy+=b[p].lazy; b[rson(p)].lazy+=b[p].lazy;
            b[p].lazy=0;
        }
    }
    void modify(int p,int l,int r,int L,int R,int v)
    {
        if (L<=l&&r<=R) {
            b[p].lazy+=v;
            b[p].sum+=v;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(p);
        if (L<=mid) modify(lson(p),l,mid,L,R,v);
        if (R>mid) modify(rson(p),mid+1,r,L,R,v);
    }
    ll getSum(int p,int l,int r,int pos)
    {
        if (l==r) return b[p].sum;
        int mid=(l+r)>>1;
        pushdown(p);
        if (pos<=mid) return getSum(lson(p),l,mid,pos);
        else return getSum(rson(p),mid+1,r,pos);
    }
    void dfs(int u,int fa)
    {
        dep[u]=dep[fa]+1;
        for (int i=0;i<v[u].size();i++) {
            d=v[u][i].first; delta=v[u][i].second;
            modify(1,1,n,dep[u],dep[u]+d,delta);
        }
        ans[u]=getSum(1,1,n,dep[u]);
        for (int i=head[u];i;i=G[i]._next) {
            int v=G[i].to;
            if (v==fa) continue;
            dfs(v,u);
        }
        for (int i=0;i<v[u].size();i++) {
            d=v[u][i].first; delta=v[u][i].second;
            modify(1,1,n,dep[u],dep[u]+d,-delta);
        }
    }
    int main()
    {
        scanf("%d",&n);
        for (int i=0;i<n-1;i++) {
            scanf("%d%d",&x,&y);
            add(x,y); add(y,x);
        }
        scanf("%d",&q);
        while (q--) {
            scanf("%d%d%d",&x,&d,&delta);
            v[x].push_back(make_pair(d,delta));
        }
        dfs(1,0);
        for (int i=1;i<=n;i++) printf("%lld ",ans[i]);
        return 0;
    }
  • 相关阅读:
    [HDU1087]Super Jumping! Jumping! Jumping!<dp>
    [codeforces]Page Numbers <模拟>
    [POJ1190]生日蛋糕<DFS>
    [HDU1029]Ignatius and the Princess IV<桶 水题>
    矩阵优化
    康复式训练
    bzoj1036 [ZJOI2008]树的统计Count
    luogu3761 [TJOI2017]城市
    bzoj2282 [SDOI2011]消防
    NOI2014
  • 原文地址:https://www.cnblogs.com/xyw5vplus1/p/12411944.html
Copyright © 2020-2023  润新知