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次操作后这个公司内每个员工的工资为多少?

解题思路:

  根据上司和下级的附属关系,可以先建一个有向图,然后对有向图进行dfs,求出每个点的dfs序列,根据序列建线段树,对于每个操作,先判断操作区间内是否需要加薪,如果需要就进行加薪操作。HINT!!!!:判定和加薪操作一定要分开,要不然会出错,比如说在一段整体不需要加薪的区间内,在线段树上,有可能前半段需要加薪,但是后半部分员工的薪水比较高。

  写代码+debug 花费了两个小时,为什么不够熟练,GG!

  1 #include <cstdio>
  2 #include <queue>
  3 #include <stack>
  4 #include <cmath>
  5 #include <cstring>
  6 #include <iostream>
  7 #include <algorithm>
  8 using namespace std;
  9
 10 typedef __int64 LL;
 11 #define lson root*2
 12 #define rson root*2+1
 13 const int maxn = 50010;
 14 const LL INF = 1e9+7;
 15
 16 struct node
 17 {
 18     int to, next;
 19 } edge[maxn*2];
 20 struct Node
 21 {
 22     int l, r;
 23     LL  sum, val;
 24     int len()
 25     {
 26         return (r - l + 1);
 27     }
 28     int mid ()
 29     {
 30         return (l + r) / 2;
 31     }
 32 } tree[maxn*4];
 33 int head[maxn], stime[maxn], etime[maxn];
 34 int tot, Max, df[maxn];
 35 LL ans[maxn], w[maxn];
 36
 37 void add (int from, int to)
 38 {
 39     edge[tot].to = to;
 40     edge[tot].next = head[from];
 41     head[from] = tot ++;
 42 }
 43 void dfs (int u)
 44 {
 45     stime[u] = ++ Max;
 46     df[Max] = u;
 47
 48     for (int i=head[u]; i!=-1; i=edge[i].next)
 49     {
 50         int v = edge[i].to;
 51         dfs (v);
 52         etime[v] = Max;
 53     }
 54 }
 55 void build (int root, int l, int r)
 56 {
 57     tree[root].l = l;
 58     tree[root].r = r;
 59     tree[root].val = 0;
 60
 61     if (l == r)
 62     {
 63         tree[root].sum = w[df[l]];
 64         return ;
 65     }
 66
 67     build (lson, l, tree[root].mid());
 68     build (rson, tree[root].mid()+1, r);
 69     tree[root].sum = tree[lson].sum + tree[rson].sum;
 70 }
 71
 72 void pushdown (int root)
 73 {
 74     if (tree[root].val == 0 || tree[root].len() == 1)
 75         return ;
 76     tree[lson].sum += tree[lson].len() * tree[root].val;
 77     tree[rson].sum += tree[rson].len() * tree[root].val;
 78     tree[lson].val += tree[root].val;
 79     tree[rson].val += tree[root].val;
 80     tree[root].val = 0;
 81 }
 82
 83 LL query (int root, int l, int r)
 84 {
 85     if (tree[root].l == l && tree[root].r == r)
 86         return tree[root].sum;
 87
 88     pushdown (root);
 89
 90     if (tree[root].mid() >= r)
 91         return query (lson, l, r);
 92     else if (tree[root].mid() < l)
 93         return query (rson, l, r);
 94     else
 95     {
 96         LL num = 0;
 97         num += query (lson, l, tree[root].mid());
 98         num += query (rson, tree[root].mid()+1, r);
 99         return num;
100     }
101 }
102 void updata (int root, int l, int r, LL x)
103 {
104     if (tree[root].l == l && tree[root].r == r)
105     {
106         tree[root].sum += tree[root].len() * x;
107         tree[root].val += x;
108         return ;
109     }
110
111     pushdown (root);
112
113     if (tree[root].mid() >= r)
114         updata (lson, l, r, x);
115     else if (tree[root].mid() < l)
116         updata (rson, l, r, x);
117     else
118     {
119         updata (lson, l, tree[root].mid(), x);
120         updata (rson, tree[root].mid()+1, r, x);
121     }
122
123     tree[root].sum = tree[lson].sum + tree[rson].sum;
124 }
125 void display (int root)
126 {
127     if (tree[root].l == tree[root].r)
128     {
129         int num = tree[root].l;
130         ans[df[num]] = tree[root].sum;
131         return ;
132     }
133
134     pushdown (root);
135     display (lson);
136     display (rson);
137 }
138
139 int main ()
140 {
141     int n, q;
142
143     while (scanf ("%d %d %I64d", &n, &q, &w[0]) != EOF)
144     {
145         memset (head, -1, sizeof(head));
146         memset (df, 0, sizeof(df));
147         memset (etime, 0, sizeof(etime));
148         tot = Max = 0;
149
150         for (int i=1; i<n; i++)
151         {
152             int u;
153             scanf ("%d %I64d", &u, &w[i]);
154             add (u, i);
155         }
156
157         dfs (0);
158         etime[0] = Max;
159         build (1, 1, n);
160
161         char str[20];
162         LL x, y, z;
163
164         while (q --)
165         {
166             scanf ("%s %I64d %I64d %I64d", str, &x, &y, &z);
167             if (strcmp (str, "employee") == 0)
168                 {
169                     LL tmp = query (1, stime[x], stime[x]);
170                     if (tmp < y)
171                         updata(1, stime[x], stime[x], z);
172                 }
173             else
174                 {
175                     LL tmp = query (1, stime[x], etime[x]);
176                     LL num = (etime[x] - stime[x] + 1) * y;
177                     if (tmp < num)
178                         updata(1, stime[x], etime[x], z);
179                 }
180         }
181
182         display (1);
183
184         for (int i=0; i<n; i++)
185             printf ("%I64d\n", ans[i]);
186     }
187     return 0;
188 }
时间: 2024-08-29 10:20:59

URAL 1890 . Money out of Thin Air (dfs序hash + 线段树)的相关文章

Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)

思路: dfs序其实是很水的东西.  和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的时候, 我们要查询一下赋值前子树最小值是不是0, 如果是的话, 要让该子树父节点变成0, 否则变0的信息会丢失. 细节参见代码: #include <cstdio> #include <cstring> #include <algorithm> #include <i

hdu4366 Successor (dfs序+zkw线段树)

Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2559    Accepted Submission(s): 613 Problem Description Sean owns a company and he is the BOSS.The other Staff has one Superior.every st

Luogu P2982 [USACO10FEB]慢下来 Slowing down | dfs序、线段树

题目链接 题目大意: 有一棵N个结点树和N头奶牛,一开始所有奶牛都在一号结点,奶牛们将按从编号1到编号N的顺序依次前往自己的目的地,求每头奶牛在去往自己目的地的途中将会经过多少已经有奶牛的结点. 题解: 可以发现,每一头奶牛到达目的地后,都只会对还未到达目的地的奶牛中,目的地在它目的地子树中的奶牛的答案产生贡献. 比如说在下面这棵树中,一头奶牛到达了图中深色结点,那么在还未到达目的地的奶牛中,只有目的地在深色结点子树中的奶牛才会由深色结点对答案产生贡献. 所以,我们可以在每头奶牛到达目的地后,将

bzoj4771 -- dfs序+倍增+主席树

先考虑没有深度限制的情况. 先将每个节点的权值设为1,对于颜色相同且在dfs序中最近的2个点,用倍增求出lca并将它的权值减一.然后子树中不同的颜色种数就是子树的权值和了. 有深度限制时,考虑以深度为时间建立主席树. 将每个点按深度排序,枚举一遍.对每种颜色开一个set,枚举到一个点时将它在dfs序中的位置加入set中并更新就可以了. 时间复杂度O(T*(nlogn+mlogn)) 代码: #include<iostream> #include<cstdio> #include&l

Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)

题目链接  Tree and Queries 题目大意  给出一棵树和每个节点的颜色.每次询问vj, kj 你需要回答在以vj为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少为kj. (莫队居然可以过) 首先转DFS序,这样就变成了区间查询. 然后直接套用莫队,求出每次询问状态下的t[],t[k]表示当前区间内拥有k个节点的颜色数量. 然后统计t[k] + t[k + 1], ..., t[MAX]即可,这个过程用树状数组维护. #include <bits/stdc++.h>

lca 欧拉序+rmq(st) 欧拉序+rmq(线段树) 离线dfs

https://www.luogu.org/problemnew/show/P3379 1.欧拉序+rmq(st) 1 /* 2 在这里,对于一个数,选择最左边的 3 选择任意一个都可以,[left_index,right_index],深度都大于等于这个数的深度 4 */ 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cmath> 8 #include <cstring> 9 #include &

【手动开栈】【dfs序】【树状数组】【Tarjan】bzoj2819 Nim

考虑树状数组区间修改(只对其子树的答案有影响)点查询,每个点记录的是它到根路径上的权值异或和. 答案时query(L)^query(R)^a[lca]. 这种方法在支持区间加法.减法的树上询问的时候可以避免树链剖分. 可能爆栈,考虑手动开栈.(诶诶Tarjan预处理lca的时候怎么没手动开栈?不要在意^_^) 实际上不会爆的. #include<cstdio> #include<stack> #include<algorithm> #include<queue&g

【dfs序】【树状数组】bzoj1103 [POI2007]大都市meg

预处理出每个点到根节点的土路数,插到一个树状数组里,然后每次修改只会对子树中的节点造成影响,于是相当于区间修改.点查询了. #include<cstdio> using namespace std; #define N 250001 int n,en,v[N<<1],next[N<<1],first[N],m; void AddEdge(const int &U,const int &V) { v[++en]=V; next[en]=first[U];

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;