这次的题目是VH难度,难度很大,不过啃下来的收获也颇多。
题意: 给出3*10^5个员工的工资,工资范围10^9,所有员工的工资必须满足如下约束:每个员工的工资不能高于其上司的工资,否则就要给其上司涨工资,使上司的工资和下属相同。
先一次给出每个员工的上司信息和工资,求涨工资的总次数。
详细描述如下(英文)
Yong is a CEO of a successful company. At first, he was the only employee of his company. However, as the business got bigger, he started to hire other employees. Now, the company has N employees excluding Yong.
In this company, employees have to call each other by number, not by name. And the numbers are given in the order that they enter the company, starting from 1 to N. The number of CEO Yong is 0. Every time a new employee gets hired, the person becomes subordinate to an existing employee. And the first salary the newly hired employee gets is decided after Yong tests his performance. If the salary of the new employee is higher than that of his superior, the salary of the superior is raised as much as the new employee’s salary. This is repeated until all the employees’ salaries become smaller than or the same with that of their superiors.
Let’s take the test case as an example. When each new employee is hired, the number of employees getting a salary raise is 0, 1, 0, 2, 4, 1 and 0 in order. When you are given the order of employment of incoming workers, their first salaries and the number of a superior, write a program that prints the sum of the number of employees who get a raise in salary whenever a new worker is hired.
[Input] The first line contains a single integer T(T ≤ 10)?the number of total test cases. The first line of each test case contains the number of employees, N (1 ≤ N ≤ 3 × 105). The second line contains the first salary of CEO Yong. The next N lines contain two integers A and B in the order of employment of new workers. A means the first salary and B indicates the number of a superior. Every salary is bigger than or equal to 1 and less than or equal to 109.
[Output] Each line begins with ‘#x’(Test case number) followed by a space and then print the sum of the number of employees who get a salary raise whenever N numbers of new workers are hired.
Input Example
1 //Number of test case
7 //N = 7
5000
4500 0
6000 0
4000 1
5500 3
7000 4
6300 2
6300 2
Output Example
#1 8 //Answer to the first test case
解法:线段树实现的RMQ作为基础查询员工的工资
二分查找员工上司中比给出工资低的最后一个员工,层数相减即为每次需刷新的次数。
参考代码如下:
1 #include <stdio.h> 2 #define SIZE 300001 3 #define MAX(a,b) ((a)>(b)?(a):(b)) 4 int tc, n, H; 5 int ancestor[SIZE][20]; 6 int visit[SIZE]; 7 int stack[2 * SIZE]; 8 int segmentTree[4 * SIZE]; 9 long long ans; 10 struct Node{ 11 int parent; 12 int last_child; 13 int brother; 14 int pay; 15 int level, depth; 16 int start, end; 17 }node[SIZE]; 18 19 int getDepth(int level){ 20 int ret = 0; 21 while (level){ 22 level /= 2; 23 ++ret; 24 } 25 return ret; 26 } 27 28 void dfs(){ 29 int top = -1, cnt = -1; 30 stack[++top] = 0; 31 while (top != -1){ 32 int index = stack[top--]; 33 if (!visit[index]){ 34 stack[++top] = index; 35 visit[index] = 1; 36 37 node[index].start = ++cnt; 38 ancestor[index][0] = node[index].parent; 39 40 for (int i = 1; i < node[index].depth; ++i) 41 ancestor[index][i] = ancestor[ancestor[index][i - 1]][i - 1]; 42 43 for (int i = node[index].last_child; i != -1; i = node[i].brother) 44 stack[++top] = i; 45 } 46 else{ 47 node[index].end = ++cnt; 48 visit[index] = 0; 49 } 50 } 51 } 52 53 void update(int index, int pay){ 54 for (int i = 0; i < H; ++i){ 55 if (segmentTree[index] >= pay)break; 56 segmentTree[index] = pay; 57 index /= 2; 58 } 59 } 60 int query(int start, int end){ 61 int ret = 0; 62 while (start < end){ 63 if (start % 2 == 1){ 64 ret = MAX(ret, segmentTree[start]); 65 ++start; 66 } 67 if (end % 2 == 0){ 68 ret = MAX(ret, segmentTree[end]); 69 --end; 70 } 71 start /= 2, end /= 2; 72 } 73 if (start == end)ret = MAX(ret, segmentTree[start]); 74 return ret; 75 } 76 77 int raise(int index){ 78 int tmpIndex = index; 79 for (int i = node[index].depth - 1; i >= 0; --i){ 80 int start = node[ancestor[tmpIndex][i]].start + 600000; 81 int end = node[ancestor[tmpIndex][i]].end + 600000; 82 83 if (query(start, end) < node[index].pay){ 84 tmpIndex = ancestor[tmpIndex][i]; 85 if (i > node[tmpIndex].depth) 86 i = node[tmpIndex].depth; 87 } 88 } 89 return node[index].level - node[tmpIndex].level; 90 } 91 92 int main(){ 93 scanf("%d", &tc); 94 for (int t = 1; t <= tc; ++t){ 95 for (int i = 0; i < 2 * n + 600000; ++i)segmentTree[i] = 0; 96 node[0].brother = node[0].last_child = -1; 97 scanf("%d", &n); 98 scanf("%d", &node[0].pay); 99 for (int i = 1; i <= n; ++i){ 100 scanf("%d%d", &node[i].pay, &node[i].parent); 101 node[i].last_child = -1; 102 node[i].level = node[node[i].parent].level + 1; 103 node[i].depth = getDepth(node[i].level); 104 node[i].brother = node[node[i].parent].last_child; 105 node[node[i].parent].last_child = i; 106 } 107 108 dfs(); 109 ans = 0; 110 H = getDepth(2 * n) + 1; 111 update(600000, node[0].pay); 112 113 for (int i = 1; i <= n; ++i){ 114 ans += raise(i); 115 update(node[i].start + 600000, node[i].pay); 116 } 117 printf("#%d %lld\n", t, ans); 118 } 119 return 0; 120 }