51Nod 1199 Money out of Thin Air(dfs序+线段树维护区间和)

这篇博客介绍了一个关于树结构的问题,涉及节点的权值更新。通过DFS序确定每个节点的管辖区间,并利用线段树来维护区间和,以处理两种类型的节点权值增加操作。给定节点数量N、操作数量M以及初始权值信息,最终求解经过所有操作后每个节点的权值。
摘要由CSDN通过智能技术生成

一棵有N个节点的树,每个节点对应1个编号及1个权值,有2种不同的操作。
操作1:S x y z,表示如果编号为x的节点的权值 < y,则将节点x的权值加上z。(Single)
操作2:A x y z,表示如果编号为x的节点以及其所有子节点的权值平均值 < y,则将节点x及其所有子节点的权值加上z。(All)
给出树节点之间的关系,进行M次操作,问所有操作完成后,各个节点的权值为多少?
节点的编号为0 - N - 1,根节点的编号为0,并且初始情况下,根节点的权值也是0。
Input
第1行:2个数N, M,N为节点的数量,M为操作的数量(1 <= N, M <= 50000)。
第2 - N行:每行描述一个节点N[i]的信息,第2行对应编号为1的节点,第N行对应编号为N - 1的节点。具体内容为:每行2个数P[i], W[i]。P[i]为当前节点的父节点的编号,W[i]为当前节点的权值。(0 <= W[i] <= 10^5, P[i] < i)
第N + 1 - N + M行:每行表示一个操作,S x y z或A x y z,(0 <= y, z <= 10^5)。
Output
输出共N行,每行1个数W[i],表示经过M次后,编号为0 - N - 1的节点的权值。
Input示例
4 3
0 10
0 10
1 2
S 0 1 1
A 0 20 1
S 3 2 1
Output示例
2
11
11
3

思路:先跑一遍dfs序,求出每个节点的管辖区间,然后线段是维护即可

#include <bits/stdc++.h>
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int mod = 998244353;
const double eps=1e-8;
const double Pi=acos(-1.0);
const int N= 50005;

struct T
{
    ll val;
    ll addmark;
} tree[N<<4];
struct node
{
    int to;
    ll val;
};
vector<node> G[N];
int L[N],R[N];
ll W[N];
int n,m,ti;
void addedge(int u,int v,ll w)
{
    G[u].push_back((node){v,w});
    G[v].push_back((node){u,w});
}
void init()
{
    ti=0;
    for(int i=0; i<=n; i++)
        G[i].clear();
    memset(L,0,sizeof(L));
    memset(R,0,sizeof(R));
    memset(W,0,sizeof(W));
    memset(tree,0,sizeof(tree));
}
void dfs(int u,int w,int per)
{
    L[u]=++ti;
    W[ti]=w;
    for(int i=0; i<(int)G[u].size(); i++)
    {
        int v=G[u][i].to;
        int c=G[u][i].val;
        if(v==per)
            continue;
        dfs(v,c,u);
    }
    R[u]=ti;
}
void build(int root,int l,int r)
{
    if(l==r)
        tree[root].val=W[l];
    else
    {
        int mid=(l+r)>>1;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
        tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
    }
}
void push_down(int root,int l,int r)
{
    if(tree[root].addmark!=0)
    {
        int mid=(l+r)>>1;
        tree[root<<1].addmark+=tree[root].addmark;
        tree[root<<1|1].addmark+=tree[root].addmark;
        tree[root<<1].val+=tree[root].addmark*(mid-l+1);
        tree[root<<1|1].val+=tree[root].addmark*(r-(mid+1)+1);
        tree[root].addmark=0;
    }
}
ll query(int root,int l,int r,int b,int e)
{
    if(b>r||e<l)
        return 0;
    if(b<=l&&r<=e)
        return tree[root].val;
    push_down(root,l,r);
    int mid=(l+r)>>1;
    ll sum=0;
    sum+=query(root<<1,l,mid,b,e);
    sum+=query(root<<1|1,mid+1,r,b,e);
    return sum;
}
void simple_updata(int root,int l,int r,int ind,ll add)
{
    if(l==r)
    {
        tree[root].val+=add;
        return ;
    }
    int mid=(l+r)>>1;
    if(ind<=mid)
        simple_updata(root<<1,l,mid,ind,add);
    else
        simple_updata(root<<1|1,mid+1,r,ind,add);
    tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
}
void interval_updata(int root,int l,int r,int b,int e,ll add)
{
    if(b>r||e<l)
        return ;
    if(b<=l&&r<=e)
    {
        tree[root].addmark+=add;
        tree[root].val+=add*(r-l+1);
        return ;
    }
    push_down(root,l,r);
    int mid=(l+r)>>1;
    interval_updata(root<<1,l,mid,b,e,add);
    interval_updata(root<<1|1,mid+1,r,b,e,add);
    tree[root].val=tree[root<<1].val+tree[root<<1|1].val;
}
int main()
{
    init();
    scanf("%d %d",&n,&m);
    int u;
    ll w;
    for(int i=1; i<n; i++)
    {
        scanf("%d %I64d",&u,&w);
        addedge(u,i,w);
    }
    dfs(0,0,-1);
//    for(int i=1;i<=n;i++)
//        printf("%d\n",W[i]);
//    for(int i=0;i<n;i++)
//        printf("i:%d L:%d R:%d\n",i,L[i],R[i]);
    build(1,1,n);
    char ch; int x; ll y,z,num;
    for(int i=0;i<m;i++)
    {
        getchar();
        scanf("%c %d %I64d %I64d",&ch,&x,&y,&z);
        if(ch=='S')
        {
            num=query(1,1,n,L[x],L[x]);
            //printf("i:%d simple:%I64d\n",i+1,num);
            if(num<y)
                simple_updata(1,1,n,L[x],z);
        }
        else if(ch=='A')
        {
            num=query(1,1,n,L[x],R[x]);
            //printf("i:%d interval:%I64d\n",i+1,num);
            if((num/(R[x]-L[x]+1))<y)
                interval_updata(1,1,n,L[x],R[x],z);
        }
    }
    for(int i=0;i<n;i++)
        printf("%I64d\n",query(1,1,n,L[i],L[i]));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值