CF 1076E Vasya and a Tree(线段树+树剖)

传送门

解题思路

  首先按照每个修改时\(x\)的深度\(+d\)从大到小排序,然后按照深度分层,一层一层的修改,修改的时候就直接暴力修改子树,然后每做完一层把答案都取下来,因为以后的所有修改的深度都小于当前层,也就是无法对当前层的节点造成贡献。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;
const int MAXN = 300005;
typedef long long LL;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}

void out(LL x){
    if(!x) return;
    out(x/10);putchar('0'+x%10);
}   

inline void OUT(LL x){
    if(!x) putchar('0');
    else out(x);
    putchar(' ');
}

int n,m,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],Max;
int dep[MAXN],fa[MAXN],son[MAXN],siz[MAXN],id[MAXN],top[MAXN],num;
LL sum[MAXN<<2],tag[MAXN<<2],ans[MAXN];
vector<int> a[MAXN];

struct Query{
    int v,d,rt;
    friend bool operator<(const Query A,const Query B){
        return A.d>B.d;
    }
}q[MAXN];

inline int max(int x,int y){
    return x>y?x:y;
}

inline int min(int x,int y){
    return x<y?x:y;
}

inline void add(int bg,int ed){
    to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}

void dfs1(int x,int f,int d){
    dep[x]=d;fa[x]=f;siz[x]=1;Max=max(Max,d);a[d].push_back(x);
    int maxson=-1,u;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==f) continue;
        dfs1(u,x,d+1);siz[x]+=siz[u];
        if(siz[u]>maxson) maxson=siz[u],son[x]=u;
    }
}

void dfs2(int x,int topf){
    top[x]=topf;id[x]=++num;int u;
    if(!son[x]) return;dfs2(son[x],topf);
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==fa[x] || u==son[x]) continue;
        dfs2(u,u);
    }
}

inline void pushdown(int x,int ln,int rn){
    tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
    sum[x<<1]+=tag[x]*ln;sum[x<<1|1]+=tag[x]*rn;
    tag[x]=0;
}

void update(int x,int l,int r,int L,int R,int k){
    if(L<=l && r<=R){
        sum[x]+=(LL)(r-l+1)*k;
        tag[x]+=k;return ;
    }
    int mid=(l+r)>>1;if(tag[x]) pushdown(x,mid-l+1,r-mid);
    if(mid>=L) update(x<<1,l,mid,L,R,k);
    if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
    sum[x]=sum[x<<1]+sum[x<<1|1];
}

LL query(int x,int l,int r,int L){
    if(l==r) return sum[x];
    int mid=(l+r)>>1;LL ret=0;if(tag[x]) pushdown(x,mid-l+1,r-mid);
    if(L<=mid) return query(x<<1,l,mid,L);
    else return query(x<<1|1,mid+1,r,L);
}

int main(){
    n=rd();int x,y,z;
    for(int i=1;i<n;i++){
        x=rd(),y=rd();
        add(x,y),add(y,x);
    }
    dfs1(1,0,1);dfs2(1,1);m=rd();
    for(int i=1;i<=m;i++){  
        x=rd(),y=rd(),z=rd();
        q[i].rt=x;q[i].d=min(dep[x]+y,Max);q[i].v=z;
    }
    sort(q+1,q+1+m);
    for(int i=1;i<=m;i++){
        x=q[i].rt,y=q[i].d,z=q[i].v;
        if(y!=q[i-1].d)
            for(int j=q[i-1].d;j>y;j--)
                for(int k=0;k<a[j].size();k++)
                    ans[a[j][k]]=query(1,1,n,id[a[j][k]]);
        update(1,1,n,id[x],id[x]+siz[x]-1,z);
    }
    for(int i=q[m].d;i;i--)
        for(int j=0;j<a[i].size();j++)
            ans[a[i][j]]=query(1,1,n,id[a[i][j]]);
    for(int i=1;i<=n;i++) OUT(ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/sdfzsyq/p/10065496.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值