51Nod 1199 Money out of Thin Air(dfs序加线段树)

http://www.51nod.com/Challenge/Problem.html#!#problemId=1199

又wa了一下午。。。

思路

树的先序遍历顺序刚好对应线段树的一个区间,利用这一点直接dfs建序,然后再建线段树来查询修改就可以了。

  1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl
  2 #define IO std::ios::sync_with_stdio(0);
  3 #include <bits/stdc++.h>
  4 #define iter ::iterator
  5 using namespace  std;
  6 typedef long long ll;
  7 typedef pair<ll,ll>P;
  8 #define pb push_back
  9 #define se second
 10 #define fi first
 11 #define rs o<<1|1
 12 #define ls o<<1
 13 const ll inf=0x7fffffff;
 14 const int N=5e4+10;
 15 int l1[N],r1[N],fa[N];
 16 ll w[N],t[N];
 17 vector<int>g[N];
 18 int n,q,cnt;
 19 struct node{
 20     ll sumv,add;
 21 }a[N*4];
 22 void dfs(int u){
 23     l1[u]=++cnt;
 24     t[cnt]=u;
 25     for(int i=0;i<g[u].size();i++){
 26         int v=g[u][i];
 27         if(v==fa[u])continue;
 28         dfs(v);
 29     }
 30     r1[u]=cnt;
 31 }
 32 void push(int o){
 33     a[o].sumv=a[ls].sumv+a[rs].sumv;
 34 }
 35 void down(int o,int l,int r){
 36     if(a[o].add){
 37         a[ls].add+=a[o].add;
 38         a[rs].add+=a[o].add;
 39         int m=(l+r)/2;
 40         a[ls].sumv+=1ll*a[o].add*(m-l+1);
 41         a[rs].sumv+=1ll*a[o].add*(r-m);
 42         a[o].add=0;
 43     }
 44 }
 45 void build(int o,int l,int r){
 46     if(l==r){
 47         a[o].sumv=w[t[l]];
 48         return;
 49     }
 50     int m=(l+r)/2;
 51     build(ls,l,m);
 52     build(rs,m+1,r);
 53     push(o);
 54 }
 55 void up(int o,int l,int r,int ql,int qr,ll k){
 56     if(l>=ql&&r<=qr){
 57         a[o].sumv+=1ll*(r-l+1)*k;
 58         a[o].add+=k;
 59         return;
 60     }
 61     down(o,l,r);
 62     int m=(l+r)/2;
 63     if(ql<=m)up(ls,l,m,ql,qr,k);
 64     if(qr>m)up(rs,m+1,r,ql,qr,k);
 65     push(o);
 66 }
 67 ll qu(int o,int l,int r,int ql,int qr){
 68     if(l>=ql&&r<=qr){
 69         return a[o].sumv;
 70     }
 71     down(o,l,r);
 72     int m=(l+r)/2;
 73     ll res=0;
 74     if(ql<=m)res+=qu(ls,l,m,ql,qr);
 75     if(qr>m)res+=qu(rs,m+1,r,ql,qr);
 76     return res;
 77 }
 78 int main(){
 79     scanf("%d%d",&n,&q);
 80     for(int i=2;i<=n;i++){
 81         scanf("%d%lld",&fa[i],&w[i]);
 82         fa[i]++;
 83         g[fa[i]].pb(i);
 84     }
 85     dfs(1);
 86     build(1,1,cnt);
 87     while(q--){
 88         char s[10];
 89         scanf("%s",s);
 90         ll x,y,z;
 91         scanf("%d%lld%lld",&x,&y,&z);
 92         x++;
 93         if(s[0]=='A'){
 94             ll res=qu(1,1,cnt,l1[x],r1[x]);
 95             ll h=r1[x]-l1[x]+1;
 96             if(res<1ll*y*h){
 97                 up(1,1,cnt,l1[x],r1[x],z);
 98             }
 99         }
100         else{
101             ll res=qu(1,1,cnt,l1[x],l1[x]);
102             if(res<y){
103                 up(1,1,cnt,l1[x],l1[x],z);
104             }
105         }
106     }
107     for(int i=1;i<=n;i++){
108         printf("%lld\n",qu(1,1,cnt,l1[i],l1[i]));
109     }
110 }

 

转载于:https://www.cnblogs.com/ccsu-kid/p/10666479.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值