51nod 1199 Money out of Thin Air(线段树+树剖分)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1199

题意:

思路:
因为是一棵树,所以需要把它剖分一下再映射到线段树上,剖分的话只需要dfs一遍树即可,得到的dfs序就是每个结点在线段树中的位置,子树上的节点的编号都是连续的。

接下来的操作就是线段树的查询和更新了,这部分并不难。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 const int INF = 0x3f3f3f3f;
 14 const int maxn=50000+5;
 15
 16 ll n, m, dfs_clock;
 17 int w[maxn],son[maxn],dfn[maxn],num[maxn];
 18 ll lazy[maxn<<2];
 19
 20 vector<int> G[maxn];
 21
 22 struct node
 23 {
 24     int l, r;
 25     ll sum;
 26 }t[maxn<<2];
 27
 28 void dfs(int u)
 29 {
 30     dfn[u]=++dfs_clock;
 31     son[u]=1;
 32     for(int i=0;i<G[u].size();i++)
 33     {
 34         int v=G[u][i];
 35         dfs(v);
 36         son[u]+=son[v];
 37     }
 38 }
 39
 40 void PushUp(int o)
 41 {
 42     t[o].sum=t[o<<1].sum+t[o<<1|1].sum;
 43 }
 44
 45 void PushDown(int o)
 46 {
 47     if(lazy[o])
 48     {
 49         lazy[o<<1]+=lazy[o];
 50         lazy[o<<1|1]+=lazy[o];
 51         int m=t[o].r-t[o].l+1;
 52         t[o<<1].sum+=lazy[o]*(m-(m>>1));
 53         t[o<<1|1].sum+=lazy[o]*(m>>1);
 54         lazy[o]=0;
 55     }
 56 }
 57
 58 void build(int l ,int r, int o)
 59 {
 60     lazy[o]=0;
 61     t[o].l=l;
 62     t[o].r=r;
 63     t[o].sum=0;
 64     if(l==r)
 65     {
 66         t[o].sum=num[l];
 67         return;
 68     }
 69     int mid=(l+r)>>1;
 70     build(l,mid,o<<1);
 71     build(mid+1,r,o<<1|1);
 72     PushUp(o);
 73 }
 74
 75 void update(int ql, int qr, int l, int r, ll z, int o)
 76 {
 77     if(ql<=l && qr>=r)
 78     {
 79         t[o].sum+=(r-l+1)*z;
 80         lazy[o]+=z;
 81         return;
 82     }
 83     PushDown(o);
 84     int mid=(l+r)>>1;
 85     if(ql<=mid)  update(ql,qr,l,mid,z,o<<1);
 86     if(qr>mid)  update(ql,qr,mid+1,r,z,o<<1|1);
 87     PushUp(o);
 88 }
 89
 90 ll query(int ql, int qr, int l, int r, int o)
 91 {
 92     if(ql<=l && qr>=r)  return t[o].sum;
 93     PushDown(o);
 94     int mid=(l+r)>>1;
 95     ll ans=0;
 96     if(ql<=mid)  ans+=query(ql,qr,l,mid,o<<1);
 97     if(qr>mid)   ans+=query(ql,qr,mid+1,r,o<<1|1);
 98     return ans;
 99 }
100
101 int main()
102 {
103     //freopen("in.txt","r",stdin);
104     scanf("%d%d",&n,&m);
105     for(int i=0;i<n;i++)  G[i].clear();
106     for(int i=1;i<n;i++)
107     {
108         int p; scanf("%d%d",&p,&w[i]);
109         G[p].push_back(i);
110     }
111     w[0]=0;
112     dfs_clock=0;
113     dfs(0);
114     for(int i=0;i<n;i++)  num[dfn[i]]=w[i];
115     build(1,n,1);
116     char op[3]; ll x, y, z;
117     memset(lazy,0,sizeof(lazy));
118     while(m--)
119     {
120         scanf("%s%lld%lld%lld",op,&x,&y,&z);
121         if(op[0]==‘S‘)
122         {
123             if(query(dfn[x],dfn[x],1,n,1)<y)  update(dfn[x],dfn[x],1,n,z,1);
124         }
125         else
126         {
127             if(query(dfn[x],dfn[x]+son[x]-1,1,n,1)<son[x]*y)  update(dfn[x],dfn[x]+son[x]-1,1,n,z,1);
128         }
129     }
130     for(int i=0;i<n;i++)  printf("%lld\n",query(dfn[i],dfn[i],1,n,1));
131     return 0;
132 }
时间: 2024-10-11 02:07:26

51nod 1199 Money out of Thin Air(线段树+树剖分)的相关文章

51nod1199 Money out of Thin Air

链剖即可.其实就是利用了链剖后子树都在一段连续的区间内所以可以做到O(logn)查询和修改. 线段树细节打错了..要专心!肉眼差错都能找出一堆出来显然是不行的!. #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(

URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)

题目链接: URAL 1890 . Money out of Thin Air 题目描述: 给出一个公司里面上司和下级的附属关系,还有每一个人的工资,然后有两种询问: 1:employee x y z ,如果编号为x的员工如果工资小于y,就给他加薪z. 2:department x y z ,如果编号为x的员工所管辖的范围内(包括自己),所有员工的工资平均数小于y,给该范围加薪z. 问q次操作后这个公司内每个员工的工资为多少? 解题思路: 根据上司和下级的附属关系,可以先建一个有向图,然后对有向

Money out of Thin Air

Money out of Thin Air Time limit: 1.0 secondMemory limit: 64 MB Each employee of the company Oceanic Airlines, except for the director, has exactly one immediate superior. To encourage the best employees and best departments, the director can issue t

51nod 1462 树据结构 | 树链剖分 矩阵乘法

题目链接 51nod 1462 题目描述 给一颗以1为根的树. 每个点有两个权值:vi, ti,一开始全部是零. Q次操作: 读入o, u, d o = 1 对u到根上所有点的vi += d o = 2 对u到根上所有点的ti += vi * d 最后,输出每个点的ti值(n, Q <= 100000) 有50%的数据N,Q <= 10000 注:所有数64位整数不会爆. 题解 这道题好神奇啊--看讨论版里的 AntiLeaf 大神的矩阵乘法打标记才找到思路,然后又看到 ccz181078 的

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

2243: [SDOI2011]染色(树链剖分+线段树)

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 8400  Solved: 3150[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C