[关闭]
@ivorysi 2018-01-02T08:34:00.000000Z 字数 32445 阅读 770

数据结构(1)学习笔记

笔记


线段树

POJ 2828 Buy Tickets

Description

Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue…
The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.
It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!
People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.

Input

There will be several test cases in the input. Each test case consists of N + 1 lines where N (1 ≤ N ≤ 200,000) is given in the first line of the test case. The next N lines contain the pairs of values Posi and Vali in the increasing order of i (1 ≤ i ≤ N). For each i, the ranges and meanings of Posi and Vali are as follows:
Posi ∈ [0, i − 1] — The i-th person came to the queue and stood right behind the Posi-th person in the queue. The booking office was considered the 0th person and the person at the front of the queue was considered the first person in the queue.
Vali ∈ [0, 32767] — The i-th person was assigned the value Vali.
There no blank lines between test cases. Proceed to the end of input.

Output

For each test cases, output a single line of space-separated integers which are the values of people in the order they stand in the queue.

Sample Input

4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492

Sample Output

77 33 69 51
31492 20523 3890 19243

Hint

The figure below shows how the Little Cat found out the final order of people in the queue described in the first test case of the sample input.

题解

这道题很秒啊!
可以考虑离线处理
最后一次插入的位置一定是准确的
从后往前处理,每次找到对应的位置即可

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #include <cmath>
  8. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  9. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  10. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  11. #define MOD 974711
  12. #define MAXN 2000005
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long ll;
  16. struct node {
  17. int l,r;
  18. int sum;
  19. }tr[MAXN*2];
  20. void build (int u,int l,int r) {
  21. tr[u].l=l;
  22. tr[u].r=r;
  23. if(l==r) {
  24. tr[u].sum=1;
  25. return;
  26. }
  27. int mid=(l+r)>>1;
  28. build(u<<1,l,mid);
  29. build(u<<1|1,mid+1,r);
  30. tr[u].sum=r-l+1;
  31. }
  32. int findpos(int u,int x) {
  33. if(tr[u].l==tr[u].r) {
  34. tr[u].sum=0;
  35. return tr[u].l;
  36. }
  37. tr[u].sum--;
  38. if(tr[u<<1].sum>=x) {
  39. return findpos(u<<1,x);
  40. }
  41. else {
  42. return findpos(u<<1|1,x-tr[u<<1].sum);
  43. }
  44. }
  45. int n;
  46. int pos[MAXN],val[MAXN];
  47. int ans[MAXN];
  48. void solve() {
  49. build(1,1,n);
  50. siji(i,1,n) {
  51. scanf("%d%d",&pos[i],&val[i]);
  52. }
  53. gongzi(i,n,1) {
  54. int x=findpos(1,pos[i]+1);
  55. ans[x]=val[i];
  56. }
  57. siji(i,1,n) {
  58. printf("%d%c",ans[i]," \n"[i==n]);
  59. }
  60. }
  61. int main() {
  62. #ifdef ivorysi
  63. freopen("f1.in","r",stdin);
  64. #endif
  65. while(scanf("%d",&n)!=EOF) {
  66. solve();
  67. }
  68. return 0;
  69. }

codeforce 717 F. Heroes of Making Magic III

I’m strolling on sunshine, yeah-ah! And doesn’t it feel good! Well, it certainly feels good for our Heroes of Making Magic, who are casually walking on a one-directional road, fighting imps. Imps are weak and feeble creatures and they are not good at much. However, Heroes enjoy fighting them. For fun, if nothing else.
Our Hero, Ignatius, simply adores imps. He is observing a line of imps, represented as a zero-indexed array of integers a of length n, where ai denotes the number of imps at the i-th position. Sometimes, imps can appear out of nowhere. When heroes fight imps, they select a segment of the line, start at one end of the segment, and finish on the other end, without ever exiting the segment. They can move exactly one cell left or right from their current position and when they do so, they defeat one imp on the cell that they moved to, so, the number of imps on that cell decreases by one. This also applies when heroes appear at one end of the segment, at the beginning of their walk.
Their goal is to defeat all imps on the segment, without ever moving to an empty cell in it (without imps), since they would get bored. Since Ignatius loves imps, he doesn’t really want to fight them, so no imps are harmed during the events of this task. However, he would like you to tell him whether it would be possible for him to clear a certain segment of imps in the above mentioned way if he wanted to.
You are given q queries, which have two types:
1 a b k — denotes that k imps appear at each cell from the interval [a, b]
2 a b - asks whether Ignatius could defeat all imps on the interval [a, b] in the way described above

Input

The first line contains a single integer n (1 ≤ n ≤ 200 000), the length of the array a. The following line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 5 000), the initial number of imps in each cell. The third line contains a single integer q (1 ≤ q ≤ 300 000), the number of queries. The remaining q lines contain one query each. Each query is provided by integers a, b and, possibly, k (0 ≤ a ≤ b < n, 0 ≤ k ≤ 5 000).

Output

For each second type of query output 1 if it is possible to clear the segment, and 0 if it is not.

Example

Input

3
2 2 2
3
2 0 2
1 1 1 1
2 0 2

Output

0
1

Note

For the first query, one can easily check that it is indeed impossible to get from the first to the last cell while clearing everything. After we add 1 to the second position, we can clear the segment, for example by moving in the following way:

题解

这算是比较难的线段树了
看完题发现根本不会

我们假定英雄都是从左边开始走,从右开始走可以作为从左走反过来



得到
然后我们发现奇数个数我们要判断这个东西是否大于1
偶数个数判断这个东西是否大于0
我们设d[i]=a[i]-a[i-1]+a[i-2]-a[i-3]+a[i-4]...到a[1]
要判断一个区间是否合法
如果r-l+1是偶数
那么的d值是d[r]+d[l-1]
这个d值需要>=0
如果r-l+1是奇数
那么的d值是d[r]-d[l-1]
这个d值需要>=1
我们可以用分成奇偶位置来维护线段树
还要维护最小值来判断中间有没有不合法的情况出现

区间加的时候对于区间内的数,如果和l奇偶性相同就+k
去过区间长度是偶数,那么这个区间后面的数都可以不考虑,如果区间长度是奇数,和l奇偶性相同的就+k和
l奇偶性不同的就-k

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #include <cmath>
  8. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  9. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  10. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  11. #define MOD 974711
  12. #define MAXN 200005
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long ll;
  16. struct node {
  17. int l,r;
  18. ll d,lazy,minq;
  19. }tr[2][MAXN*10];
  20. int n,q;
  21. ll a[MAXN];
  22. typedef int (*pf) (int);
  23. void build(int now,int u,int l,int r,pf cur) {
  24. tr[now][u].l=l;
  25. tr[now][u].r=r;
  26. if(l==r) {
  27. tr[now][u].d=a[cur(l)];
  28. tr[now][u].minq=a[cur(l)];
  29. return;
  30. }
  31. int mid=(l+r)>>1;
  32. build(now,u<<1,l,mid,cur);
  33. build(now,u<<1|1,mid+1,r,cur);
  34. tr[now][u].minq=min(tr[now][u<<1].minq,tr[now][u<<1|1].minq);
  35. }
  36. int op1(int k) {
  37. return k*2;
  38. }
  39. int op2(int k) {
  40. return k*2-1;
  41. }
  42. void pushnode(int now,int u) {
  43. if(tr[now][u].lazy!=0) {
  44. tr[now][u<<1].d+=tr[now][u].lazy;
  45. tr[now][u<<1|1].d+=tr[now][u].lazy;
  46. tr[now][u<<1].minq+=tr[now][u].lazy;
  47. tr[now][u<<1|1].minq+=tr[now][u].lazy;
  48. tr[now][u<<1].lazy+=tr[now][u].lazy;
  49. tr[now][u<<1|1].lazy+=tr[now][u].lazy;
  50. tr[now][u].lazy=0;
  51. }
  52. }
  53. ll findval(int now,int u,int x,pf cur) {
  54. if(tr[now][u].l==tr[now][u].r) {
  55. return tr[now][u].d;
  56. }
  57. pushnode(now,u);
  58. int mid=(tr[now][u].l+tr[now][u].r)>>1;
  59. if(cur(mid)>=x) {
  60. return findval(now,u<<1,x,cur);
  61. }
  62. else {
  63. return findval(now,u<<1|1,x,cur);
  64. }
  65. }
  66. ll qmin(int now,int u,int l,int r) {
  67. if(tr[now][u].l==l && tr[now][u].r==r) {
  68. return tr[now][u].minq;
  69. }
  70. pushnode(now,u);
  71. int mid=(tr[now][u].l+tr[now][u].r)>>1;
  72. if(mid>=r) {
  73. return qmin(now,u<<1,l,r);
  74. }
  75. else if(mid<l) {
  76. return qmin(now,u<<1|1,l,r);
  77. }
  78. else {
  79. return min(qmin(now,u<<1,l,mid),qmin(now,u<<1|1,mid+1,r));
  80. }
  81. }
  82. ll getnode(int x) {
  83. if(x==0) return 0;
  84. if(x%2==0) {
  85. return findval(0,1,x,op1);
  86. }
  87. else {
  88. return findval(1,1,x,op2);
  89. }
  90. }
  91. void change(int now,int u,int l,int r,ll k) {
  92. if(tr[now][u].l==l && tr[now][u].r==r) {
  93. tr[now][u].lazy+=k;
  94. tr[now][u].minq+=k;
  95. tr[now][u].d+=k;
  96. return;
  97. }
  98. pushnode(now,u);
  99. int mid=(tr[now][u].l+tr[now][u].r)>>1;
  100. if(mid>=r) {
  101. change(now,u<<1,l,r,k);
  102. }
  103. else if(mid<l) {
  104. change(now,u<<1|1,l,r,k);
  105. }
  106. else {
  107. change(now,u<<1,l,mid,k);
  108. change(now,u<<1|1,mid+1,r,k);
  109. }
  110. tr[now][u].minq=min(tr[now][u<<1].minq,tr[now][u<<1|1].minq);
  111. }
  112. int leftpos_odd(int l) {//这道题直接算点是做不到的……
  113. if(l%2==0) ++l;
  114. return (l+1)/2;
  115. }
  116. int rightpos_odd(int r) {
  117. if(r%2==0) --r;
  118. return (r+1)/2;
  119. }
  120. int leftpos_even(int l) {
  121. if(l%2) ++l;
  122. return l/2;
  123. }
  124. int rightpos_even(int r) {
  125. if(r%2) --r;
  126. return r/2;
  127. }
  128. void solve() {
  129. scanf("%d",&n);
  130. siji(i,1,n) {
  131. scanf("%lld",&a[i]);
  132. }
  133. siji(i,2,n) {
  134. a[i]=a[i]-a[i-1];
  135. }
  136. build(0,1,leftpos_even(1),rightpos_even(n),op1);
  137. build(1,1,leftpos_odd(1),rightpos_odd(n),op2);
  138. scanf("%d",&q);
  139. int op,a,b;
  140. ll k;
  141. siji(i,1,q) {
  142. if(scanf("%d%d%d",&op,&a,&b)==EOF) break;
  143. ++a,++b;
  144. if(op==1) {
  145. scanf("%lld",&k);
  146. int now=a%2;
  147. if(now==1) {
  148. change(now,1,leftpos_odd(a),rightpos_odd(b),k);
  149. }
  150. else {
  151. change(now,1,leftpos_even(a),rightpos_even(b),k);
  152. }
  153. if((b-a+1)%2) {
  154. ++b;
  155. if(b>n) continue;
  156. if(a%2==0) {
  157. if(rightpos_even(n)>=leftpos_even(b)) {
  158. change(0,1,leftpos_even(b),rightpos_even(n),k);
  159. }
  160. if(rightpos_odd(n)>=leftpos_odd(b)) {
  161. change(1,1,leftpos_odd(b),rightpos_odd(n),-k);
  162. }
  163. }
  164. else {
  165. if(rightpos_even(n)>=leftpos_even(b)) {
  166. change(0,1,leftpos_even(b),rightpos_even(n),-k);
  167. }
  168. if(rightpos_odd(n)>=leftpos_odd(b)) {
  169. change(1,1,leftpos_odd(b),rightpos_odd(n),k);
  170. }
  171. }
  172. }
  173. }
  174. else {
  175. ll d1=getnode(b),d2=getnode(a-1);
  176. if(a==b) {
  177. d1+=d2;
  178. if(d1!=1) puts("0");
  179. else puts("1");
  180. continue;
  181. }
  182. ll t1,t2;
  183. if(rightpos_even(b)>=leftpos_even(a)) {
  184. t1=qmin(0,1,leftpos_even(a),rightpos_even(b));
  185. if((a-1)%2==0 && t1-d2<0) {puts("0");continue;}
  186. if((a-1)%2==1 && t1+d2<1) {puts("0");continue;}
  187. }
  188. if(rightpos_odd(b)>=leftpos_odd(a)) {
  189. t2=qmin(1,1,leftpos_odd(a),rightpos_odd(b));
  190. if((a-1)%2==1 && t2-d2<0) {puts("0");continue;}
  191. if((a-1)%2==0 && t2+d2<1) {puts("0");continue;}
  192. }
  193. int len=b-a+1;
  194. if(len%2==0) {
  195. d1-=d2;
  196. }
  197. else {
  198. d1+=d2;
  199. }
  200. if(d1==(len%2)) puts("1");
  201. else puts("0");
  202. }
  203. }
  204. }
  205. int main() {
  206. #ifdef ivorysi
  207. freopen("f1.in","r",stdin);
  208. #endif
  209. solve();
  210. return 0;
  211. }

codeforce 498 D. Traffic Jams in the Land

Some country consists of (n + 1) cities, located along a straight highway. Let's number the cities with consecutive integers from 1 to n + 1 in the order they occur along the highway. Thus, the cities are connected by n segments of the highway, the i-th segment connects cities number i and i + 1. Every segment of the highway is associated with a positive integer ai > 1 — the period of traffic jams appearance on it.
In order to get from city x to city y (x < y), some drivers use the following tactics.
Initially the driver is in city x and the current time t equals zero. Until the driver arrives in city y, he perfors the following actions:
if the current time t is a multiple of ax, then the segment of the highway number x is now having traffic problems and the driver stays in the current city for one unit of time (formally speaking, we assign t = t + 1);
if the current time t is not a multiple of ax, then the segment of the highway number x is now clear and that's why the driver uses one unit of time to move to city x + 1 (formally, we assign t = t + 1 and x = x + 1).
You are developing a new traffic control system. You want to consecutively process q queries of two types:
determine the final value of time t after the ride from city x to city y (x < y) assuming that we apply the tactics that is described above. Note that for each query t is being reset to 0.
replace the period of traffic jams appearing on the segment number x by value y (formally, assign ax = y).
Write a code that will effectively process the queries given above.

Input

The first line contains a single integer n (1 ≤ n ≤ 105) — the number of highway segments that connect the n + 1 cities.
The second line contains n integers a1, a2, ..., an (2 ≤ ai ≤ 6) — the periods of traffic jams appearance on segments of the highway.
The next line contains a single integer q (1 ≤ q ≤ 105) — the number of queries to process.
The next q lines contain the descriptions of the queries in the format c, x, y (c — the query type).
If c is character 'A', then your task is to process a query of the first type. In this case the following constraints are satisfied: 1 ≤ x < y ≤ n + 1.
If c is character 'C', then you need to process a query of the second type. In such case, the following constraints are satisfied: 1 ≤ x ≤ n, 2 ≤ y ≤ 6.

Output

For each query of the first type output a single integer — the final value of time t after driving from city x to city y. Process the queries in the order in which they are given in the input.

题解

这道题建60棵线段树,因为2 3 4 5 6的最大公倍数是60
[l,r]区间表示从l开始值%60开始所要花的最大时间
每次更新区间更新60次
然后用左区间用的时间+当前时间赋给右区间去累加

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #include <cmath>
  8. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  9. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  10. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  11. #define MOD 974711
  12. #define MAXN 100005
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long ll;
  16. struct node {
  17. int l,r;
  18. int val[60];
  19. }tr[MAXN*4];
  20. int n,q;
  21. int a[MAXN],x,y;
  22. char str[5];
  23. void build(int u,int l,int r) {
  24. tr[u].l=l;tr[u].r=r;
  25. if(l==r) {
  26. siji(i,0,59) {
  27. tr[u].val[i]=1+(i%a[l]==0);
  28. }
  29. return;
  30. }
  31. int mid=(l+r)>>1;
  32. build(u<<1,l,mid);
  33. build(u<<1|1,mid+1,r);
  34. siji(i,0,59) {
  35. int lsum=tr[u<<1].val[i];
  36. int rsum=tr[u<<1|1].val[(i+lsum)%60];
  37. tr[u].val[i]=lsum+rsum;
  38. }
  39. return;
  40. }
  41. void changepos(int u,int x) {
  42. if(tr[u].l==tr[u].r) {
  43. siji(i,0,59) {
  44. tr[u].val[i]=1+(i%a[x]==0);
  45. }
  46. return;
  47. }
  48. int mid=(tr[u].l+tr[u].r)>>1;
  49. if(x<=mid) {
  50. changepos(u<<1,x);
  51. }
  52. else {
  53. changepos(u<<1|1,x);
  54. }
  55. siji(i,0,59) {
  56. int lsum=tr[u<<1].val[i];
  57. int rsum=tr[u<<1|1].val[(i+lsum)%60];
  58. tr[u].val[i]=lsum+rsum;
  59. }
  60. }
  61. int query(int u,int l,int r,int s) {
  62. if(tr[u].l==l && tr[u].r==r) {
  63. return tr[u].val[s];
  64. }
  65. int mid=(tr[u].l+tr[u].r)>>1;
  66. if(r<=mid) {
  67. return query(u<<1,l,r,s);
  68. }
  69. else if(l>mid) {
  70. return query(u<<1|1,l,r,s);
  71. }
  72. else {
  73. int lsum=query(u<<1,l,mid,s);
  74. int rsum=query(u<<1|1,mid+1,r,(s+lsum)%60);
  75. return lsum+rsum;
  76. }
  77. }
  78. void solve() {
  79. scanf("%d",&n);
  80. siji(i,1,n) {
  81. scanf("%d",&a[i]);
  82. }
  83. build(1,1,n);
  84. scanf("%d",&q);
  85. siji(i,1,q) {
  86. scanf("%s",str+1);
  87. scanf("%d%d",&x,&y);
  88. if(str[1]=='A') {
  89. --y;
  90. printf("%d\n",query(1,x,y,0));
  91. }
  92. else {
  93. a[x]=y;
  94. changepos(1,x);
  95. }
  96. }
  97. }
  98. int main() {
  99. #ifdef ivorysi
  100. freopen("f1.in","r",stdin);
  101. #endif
  102. solve();
  103. return 0;
  104. }

树状数组

POJ 1990 MooFest

Description

Every year, Farmer John's N (1 <= N <= 20,000) cows attend "MooFest",a social gathering of cows from around the world. MooFest involves a variety of events including haybale stacking, fence jumping, pin the tail on the farmer, and of course, mooing. When the cows all stand in line for a particular event, they moo so loudly that the roar is practically deafening. After participating in this event year after year, some of the cows have in fact lost a bit of their hearing.
Each cow i has an associated "hearing" threshold v(i) (in the range 1..20,000). If a cow moos to cow i, she must use a volume of at least v(i) times the distance between the two cows in order to be heard by cow i. If two cows i and j wish to converse, they must speak at a volume level equal to the distance between them times max(v(i),v(j)).
Suppose each of the N cows is standing in a straight line (each cow at some unique x coordinate in the range 1..20,000), and every pair of cows is carrying on a conversation using the smallest possible volume.
Compute the sum of all the volumes produced by all N(N-1)/2 pairs of mooing cows.

Input

  • Line 1: A single integer, N
  • Lines 2..N+1: Two integers: the volume threshold and x coordinate for a cow. Line 2 represents the first cow; line 3 represents the second cow; and so on. No two cows will stand at the same location.

Output

  • Line 1: A single line with a single integer that is the sum of all the volumes of the conversing cows.

Sample Input

4
3 1
2 5
2 6
4 3

Sample Output

57

题解

这道题把v从小到大排序
然后求去在它前面的点到它的距离总和,在它后面的点到它的距离总和
两个树状数组即可

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #include <cmath>
  8. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  9. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  10. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  11. #define MOD 974711
  12. #define MAXN 20005
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long ll;
  16. struct node {
  17. int v,x;
  18. bool operator < (const node &rhs) const{
  19. return v<rhs.v;
  20. }
  21. }cow[MAXN];
  22. ll tr1[MAXN],tr2[MAXN],ans;
  23. int n;
  24. int lowbit(int x) {return x&(-x);}
  25. void change(ll *cur,int pos,ll x) {
  26. while(pos<=20000) {
  27. cur[pos]+=x;
  28. pos+=lowbit(pos);
  29. }
  30. }
  31. ll getval(ll *cur,int pos){
  32. ll res=0;
  33. while(pos) {
  34. res+=cur[pos];
  35. pos-=lowbit(pos);
  36. }
  37. return res;
  38. }
  39. ll query(ll *cur,int l,int r) {
  40. return getval(cur,r)-getval(cur,l-1);
  41. }
  42. void solve() {
  43. scanf("%d",&n);
  44. siji(i,1,n) {
  45. scanf("%d%d",&cow[i].v,&cow[i].x);
  46. }
  47. sort(cow+1,cow+n+1);
  48. siji(i,1,n) {
  49. ll len=(query(tr1,1,cow[i].x-1)*cow[i].x-query(tr2,1,cow[i].x-1))+
  50. (query(tr2,cow[i].x+1,20000)-query(tr1,cow[i].x+1,20000)*cow[i].x);
  51. len=len*cow[i].v;
  52. ans+=len;
  53. change(tr1,cow[i].x,1);
  54. change(tr2,cow[i].x,cow[i].x);
  55. }
  56. printf("%lld\n",ans);
  57. }
  58. int main() {
  59. #ifdef ivorysi
  60. freopen("f1.in","r",stdin);
  61. #endif
  62. solve();
  63. return 0;
  64. }

ST表

codeforce 359 D. Pair of Numbers

Simon has an array a1, a2, ..., an, consisting of n positive integers. Today Simon asked you to find a pair of integers l, r (1 ≤ l ≤ r ≤ n), such that the following conditions hold:

there is integer j (l ≤ j ≤ r), such that all integers al, al + 1, ..., ar are divisible by aj;
value r - l takes the maximum value among all pairs for which condition 1 is true; 

Help Simon, find the required pair of numbers (l, r). If there are multiple required pairs find all of them.

Input

The first line contains integer n (1 ≤ n ≤ 3·105).
The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 106).

Output

Print two integers in the first line — the number of required pairs and the maximum value of r - l. On the following line print all l values from optimal pairs in increasing order.
Examples

Input

5
4 6 9 3 6

Output

1 3
2

Input

5
1 3 5 7 9

Output

1 4
1

Input

5
2 3 5 7 11

Output

5 0
1 2 3 4 5

Note

In the first sample the pair of numbers is right, as numbers 6, 9, 3 are divisible by 3.
In the second sample all numbers are divisible by number 1.
In the third sample all numbers are prime, so conditions 1 and 2 are true only for pairs of numbers (1, 1), (2, 2), (3, 3), (4, 4), (5, 5).

题解

这个区间所有的数的gcd和最小值是一个的话那么这个区间就是合法的
用st表维护就行,二分答案

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  8. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  9. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  10. #define MOD 974711
  11. #define MAXN 300005
  12. //#define ivorysi
  13. using namespace std;
  14. typedef long long ll;
  15. int n;
  16. int a[MAXN];
  17. int st1[MAXN][25],st2[MAXN][25];
  18. int log2[MAXN];
  19. vector<int> v;
  20. int gcd(int a,int b) {
  21. return b==0 ? a:gcd(b,a%b);
  22. }
  23. int query1(int a,int b) {
  24. int l=log2[b-a+1];
  25. return gcd(st1[a][l],st1[b-(1<<l)+1][l]);
  26. }
  27. int query2(int a,int b) {
  28. int l=log2[b-a+1];
  29. return min(st2[a][l],st2[b-(1<<l)+1][l]);
  30. }
  31. bool check(int x) {
  32. siji(i,1,n) {
  33. if(i+x>n) return false;
  34. if(query1(i,i+x)==query2(i,i+x)) {
  35. return true;
  36. }
  37. }
  38. return false;
  39. }
  40. void solve() {
  41. scanf("%d",&n);
  42. siji(i,1,n) {
  43. scanf("%d",&a[i]);
  44. }
  45. siji(i,2,n) {
  46. int t=i;
  47. int l=0;
  48. while(t) {++l;t>>=1;}
  49. --l;
  50. log2[i]=l;
  51. }
  52. siji(i,1,n) {
  53. st1[i][0]=a[i];
  54. st2[i][0]=a[i];
  55. }
  56. siji(j,1,20) {
  57. siji(i,1,n) {
  58. if(i+(1<<j)-1 > n) break;
  59. st1[i][j]=gcd(st1[i][j-1],st1[i+(1<<(j-1))][j-1]);
  60. st2[i][j]=min(st2[i][j-1],st2[i+(1<<(j-1))][j-1]);
  61. }
  62. }
  63. int l=0,r=n-1;
  64. while(l<r) {
  65. int mid=(l+r+1)>>1;
  66. if(check(mid)) l=mid;
  67. else r=mid-1;
  68. }
  69. siji(i,1,n) {
  70. if(i+l>n) break;
  71. if(query1(i,i+l)==query2(i,i+l)) {
  72. v.push_back(i);
  73. }
  74. }
  75. int s=v.size();
  76. printf("%d %d\n",s,l);
  77. xiaosiji(i,0,s) {
  78. printf("%d%c",v[i]," \n"[i==s-1]);
  79. }
  80. }
  81. int main() {
  82. #ifdef ivorysi
  83. freopen("f1.in","r",stdin);
  84. #endif
  85. solve();
  86. return 0;
  87. }

左偏树

如何愉快的书写这个比堆还好写的可并堆呢
两个堆合并的话(假设小根堆)
如果A或B一个堆为空,返回另一个
我们将A的右儿子和B合并(如果A的根权值比B大就交换AB)
然后比较A左右子树的距离,如果右子树的距离比较大,把左右子树交换
更新A的距离
返回A

删除根节点只需要合并两个子树就好了

BZOJ 2809: [Apio2012]dispatching

Description

在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。在这个帮派里,有一名忍者被称之为 Master。除了 Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者 支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者 发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递 人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,就不需要支付管理者的薪水。你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。写一个程序,给定每一个忍者 i的上级 Bi,薪水Ci,领导力L i,以及支付给忍者们的薪水总预算 M,输出在预算内满足上述要求时顾客满意度的最大值。
1 ≤N ≤ 100,000 忍者的个数;
1 ≤M ≤ 1,000,000,000 薪水总预算;
0 ≤Bi < i 忍者的上级的编号;
1 ≤Ci ≤ M 忍者的薪水;
1 ≤Li ≤ 1,000,000,000 忍者的领导力水平。

Input

从标准输入读入数据。
第一行包含两个整数 N和 M,其中 N表示忍者的个数,M表示薪水的总预算。
接下来 N行描述忍者们的上级、薪水以及领导力。其中的第 i 行包含三个整 Bi , C i , L i分别表示第i个忍者的上级,薪水以及领导力。Master满足B i = 0,并且每一个忍者的老板的编号一定小于自己的编号 Bi < i。

Output

输出一个数,表示在预算内顾客的满意度的最大值。

Sample Input

5 4
0 3 3
1 3 5
2 2 2
1 2 4
2 3 1

Sample Output

6

题解

选择一个树上的点,然后选择这个树的一些子节点,这些子节点的和不超过m
然后我们可以对每个子树建一个左偏树,如果左偏树的总和大于m,就不断删除最大值直到总和小于m
然后更新ans就可以了

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  8. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  9. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  10. #define MOD 974711
  11. #define MAXN 100005
  12. //#define ivorysi
  13. using namespace std;
  14. typedef long long ll;
  15. struct node {
  16. node *lc,*rc;
  17. int dist,size,val;
  18. long long sum;
  19. node() {}
  20. node(const int &c) {
  21. lc=NULL,rc=NULL,dist=0,size=1,val=c,sum=c;
  22. }
  23. inline void update() {
  24. sum=val,size=1;
  25. if(lc!=NULL)sum+=lc->sum,size+=lc->size;
  26. if(rc!=NULL)sum+=rc->sum,size+=rc->size;
  27. }
  28. }*tr[MAXN];
  29. struct data {
  30. int to,next;
  31. }edge[MAXN+5];
  32. int head[MAXN],sumedge;
  33. void add(int u,int v) {
  34. edge[++sumedge].to=v;
  35. edge[sumedge].next=head[u];
  36. head[u]=sumedge;
  37. }
  38. int n;
  39. int lead[MAXN],fa[MAXN],calc[MAXN],rt,que[MAXN],ql;
  40. ll budget,ans;
  41. int getdist(node *z){
  42. if(z==NULL) return -1;
  43. else return z->dist;
  44. }
  45. node* merge(node* A,node* B) {
  46. if(A==NULL) return B;
  47. if(B==NULL) return A;
  48. if(A->val < B->val) swap(A,B);
  49. A->rc=merge(A->rc,B);
  50. if(getdist(A->rc) > getdist(A->lc)) {
  51. swap(A->rc,A->lc);
  52. }
  53. A->dist=getdist(A->rc)+1;
  54. A->update();
  55. return A;
  56. }
  57. void balance(node *&x) {
  58. while(x->sum > budget) {
  59. x=merge(x->lc,x->rc);
  60. }
  61. }
  62. void solve() {
  63. scanf("%d%lld",&n,&budget);
  64. siji(i,1,n) {
  65. scanf("%d%d%d",&fa[i],&calc[i],&lead[i]);
  66. if(fa[i]==0) rt=i;
  67. else add(fa[i],i);
  68. tr[i]=new node(calc[i]);
  69. }
  70. que[++ql]=rt;
  71. siji(u,1,ql) {
  72. for(int i=head[u];i;i=edge[i].next) {
  73. que[++ql]=edge[i].to;
  74. }
  75. }
  76. gongzi(i,ql,2) {
  77. int now=que[i],y=fa[now];
  78. ans=max(ans,(ll)tr[now]->size*lead[now]);
  79. tr[y]=merge(tr[now],tr[y]);
  80. balance(tr[y]);
  81. }
  82. ans=max(ans,(ll)tr[rt]->size*lead[rt]);
  83. printf("%lld\n",ans);
  84. }
  85. int main() {
  86. #ifdef ivorysi
  87. freopen("f1.in","r",stdin);
  88. #endif
  89. solve();
  90. return 0;
  91. }

POJ3666 Making the Grade

Description

A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).
You are given N integers A1, ... , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . ... , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is
|A1 - B1| + |A2 - B2| + ... + |AN - BN |
Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.

Input

  • Line 1: A single integer: N
  • Lines 2..N+1: Line i+1 contains a single integer elevation: Ai

Output

  • Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.

Sample Input

7
1
3
2
4
5
3
9

Sample Output

3

题解

这道题我们要考虑两种情况
就按照如果我们要恢复的序列是非下降序列
如果a[1]<=a[2]<=a[3]<=a[4]...<=a[n]
那么我们这个序列显然不用动了
如果a[1]>a[2]>a[3]>a[4]...>a[n]
我们可以把这个区间全部改为这个区间的中位数
这样一定是最优的因为我们必须把区间修改成同一个数
然后我们的区间划分成为若干个下降序列(可以只有一个点)
如果这两个下降序列的中位数非下降,我们可以直接合并这两个区间
否则我们需要把这两个区间合并,找它们的中位数
为什么是对的呢,因为如果前面的区间的值如果大于后面的区间,后面的区间需要整体提升,然后提升到和前面的区间值一样为止
但是反正都是一样的值了,最优解就是他们的中位数
然后我们用一个队列维护一个区间,一个点建立一个区间
然后拿这个区间和队尾比较,如果这个点比前一个小,那么合并这个两个区间,直到这个队列里区间的中位数单调不下降
维护中位数用左偏树,如果左偏树里区间个数大于一半就删除

非上升序列也同理

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  8. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  9. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  10. #define MOD 974711
  11. #define MAXN 100005
  12. //#define ivorysi
  13. using namespace std;
  14. typedef long long ll;
  15. struct node {
  16. node *lc,*rc;
  17. int dist,size,val;
  18. node() {};
  19. node(const int &v) {
  20. val=v;size=1;dist=0;lc=NULL;rc=NULL;
  21. }
  22. void update() {
  23. size=1;
  24. if(lc!=NULL) size+=lc->size;
  25. if(rc!=NULL) size+=rc->size;
  26. }
  27. }*tr[MAXN];
  28. int n;
  29. int a[MAXN];
  30. int getdist(node *z){
  31. if(z==NULL) return -1;
  32. else return z->dist;
  33. }
  34. node* merge(node* A,node* B) {
  35. if(A==NULL) return B;
  36. if(B==NULL) return A;
  37. if(A->val < B->val) swap(A,B);
  38. A->rc=merge(A->rc,B);
  39. if(getdist(A->rc) > getdist(A->lc)) {
  40. swap(A->rc,A->lc);
  41. }
  42. A->dist=getdist(A->rc)+1;
  43. A->update();
  44. return A;
  45. }
  46. void balance(node *&x,int len) {
  47. if(len%2) len=len/2+1;
  48. else len/=2;
  49. while(x->size>len) {
  50. x=merge(x->lc,x->rc);
  51. }
  52. }
  53. int b[MAXN];
  54. int que[MAXN],ql;
  55. ll ans;
  56. void solve() {
  57. scanf("%d",&n);
  58. siji(i,1,n) {
  59. scanf("%d",&a[i]);
  60. }
  61. ql=0;
  62. siji(i,1,n) {
  63. b[i]=a[i];
  64. tr[i]=new node(a[i]);
  65. while(ql>0 && b[i]<b[que[ql]]) {
  66. tr[i]=merge(tr[i],tr[que[ql]]);
  67. --ql;
  68. balance(tr[i],i-que[ql]);
  69. b[i]=tr[i]->val;
  70. }
  71. que[++ql]=i;
  72. }
  73. int p=1,t=1;
  74. while(p<=n) {
  75. b[p]=b[que[t]];
  76. if(p==que[t]) ++t;
  77. ++p;
  78. }
  79. siji(i,1,n) {
  80. ans+=abs(a[i]-b[i]);
  81. }
  82. memset(tr,0,sizeof(tr));
  83. ql=0;
  84. siji(i,1,n) {
  85. b[i]=a[i];
  86. tr[i]=new node(a[i]);
  87. while(ql>0 && b[i]>b[que[ql]]) {
  88. tr[i]=merge(tr[i],tr[que[ql]]);
  89. --ql;
  90. balance(tr[i],i-que[ql]);
  91. b[i]=tr[i]->val;
  92. }
  93. que[++ql]=i;
  94. }
  95. p=1,t=1;
  96. while(p<=n) {
  97. b[p]=b[que[t]];
  98. if(p==que[t])++t;
  99. ++p;
  100. }
  101. ll tmp=0;
  102. siji(i,1,n) {
  103. tmp+=abs(a[i]-b[i]);
  104. }
  105. ans=min(ans,tmp);
  106. printf("%lld\n",ans);
  107. }
  108. int main() {
  109. #ifdef ivorysi
  110. freopen("f1.in","r",stdin);
  111. #endif
  112. solve();
  113. return 0;
  114. }

树链剖分

一些要用的部分分别是
fa 每个点的父亲
size 每个点子树的大小(用来更新重儿子)
son 每个点的重儿子
dep 每个点的深度(用来爬树)
belong 每个点属于哪条链
top 这条链的顶端
lroot 这条链树根的编号

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 a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

Sample Output

3
1
2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

题解

树链剖分又一道板子题级别的题
我们维护这个区间左右端点的颜色,如果左区间的右端点颜色和右区间的左端点颜色相同统计数就减一

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #include <cmath>
  8. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  9. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  10. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  11. #define MOD 974711
  12. #define MAXN 100005
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long ll;
  16. struct treenode {
  17. int l,r,
  18. lson,
  19. rson,
  20. lcol,
  21. rcol,
  22. sum,
  23. setcol;
  24. bool lazy;
  25. }tr[MAXN*10];
  26. int treecnt;
  27. void update(int u) {
  28. int ls=tr[u].lson,rs=tr[u].rson;
  29. tr[u].sum=tr[ls].sum+tr[rs].sum;
  30. if(tr[ls].rcol==tr[rs].lcol) --tr[u].sum;
  31. tr[u].lcol=tr[ls].lcol;
  32. tr[u].rcol=tr[rs].rcol;
  33. }
  34. void pushnode(int u) {
  35. if(tr[u].lazy) {
  36. int ls=tr[u].lson,rs=tr[u].rson;
  37. tr[ls].sum=1;tr[ls].lcol=tr[ls].rcol=tr[u].setcol;
  38. tr[rs].sum=1;tr[rs].lcol=tr[rs].rcol=tr[u].setcol;
  39. tr[ls].lazy=tr[rs].lazy=1;
  40. tr[ls].setcol=tr[rs].setcol=tr[u].setcol;
  41. tr[u].setcol=0;tr[u].lazy=0;
  42. }
  43. }
  44. int dep[MAXN],
  45. fa[MAXN],
  46. size[MAXN],
  47. son[MAXN],
  48. rnk[MAXN],
  49. belong[MAXN],
  50. top[MAXN],
  51. linkcnt,
  52. lroot[MAXN];
  53. int n,col[MAXN],m;
  54. struct node {
  55. int to,next;
  56. }edge[MAXN*2];
  57. int head[MAXN],sumedge;
  58. void add(int u,int v) {
  59. edge[++sumedge].to=v;
  60. edge[sumedge].next=head[u];
  61. head[u]=sumedge;
  62. }
  63. void addtwo(int u,int v) {
  64. add(u,v);
  65. add(v,u);
  66. }
  67. void dfs1(int u){
  68. size[u]=1;
  69. for(int i=head[u];i;i=edge[i].next) {
  70. int v=edge[i].to;
  71. if(v!=fa[u]) {
  72. fa[v]=u;
  73. dep[v]=dep[u]+1;
  74. dfs1(v);
  75. size[u]+=size[v];
  76. if(size[v]>size[son[u]]) son[u]=v;
  77. }
  78. }
  79. }
  80. void build(int u,int l,int r);
  81. vector<int> line;
  82. void dfs2(int u) {
  83. if(!belong[u]) {
  84. belong[u]=++linkcnt;
  85. top[belong[u]]=u;
  86. rnk[u]=1;
  87. }
  88. line.push_back(u);
  89. if(!son[u]) {
  90. lroot[belong[u]]=++treecnt;
  91. build(treecnt,1,rnk[u]);
  92. line.clear();
  93. return;
  94. }
  95. belong[son[u]]=belong[u];
  96. rnk[son[u]]=rnk[u]+1;
  97. dfs2(son[u]);
  98. for(int i=head[u];i;i=edge[i].next) {
  99. int v=edge[i].to;
  100. if(v!=son[u] && v!=fa[u]) {
  101. dfs2(v);
  102. }
  103. }
  104. }
  105. void build(int u,int l,int r) {
  106. tr[u].l=l;tr[u].r=r;
  107. if(l==r) {
  108. tr[u].sum=1;
  109. tr[u].lcol=col[line[l-1]];
  110. tr[u].rcol=col[line[l-1]];
  111. tr[u].lazy=0;
  112. return;
  113. }
  114. int mid=(l+r)>>1;
  115. tr[u].lson=++treecnt;tr[u].rson=++treecnt;
  116. build(tr[u].lson,l,mid);
  117. build(tr[u].rson,mid+1,r);
  118. update(u);
  119. }
  120. int query_tree(int u,int l,int r) {
  121. if(l==tr[u].l && r==tr[u].r) {
  122. return tr[u].sum;
  123. }
  124. int mid=(tr[u].l+tr[u].r)>>1;
  125. int ls=tr[u].lson,rs=tr[u].rson;
  126. pushnode(u);
  127. if(mid>=r) {
  128. return query_tree(ls,l,r);
  129. }
  130. else if(l>mid) {
  131. return query_tree(rs,l,r);
  132. }
  133. else {
  134. return query_tree(ls,l,mid)+query_tree(rs,mid+1,r)-(tr[ls].rcol==tr[rs].lcol);
  135. }
  136. }
  137. int ask_color(int u,int x) {
  138. if(tr[u].l==tr[u].r) {
  139. return tr[u].lcol;
  140. }
  141. pushnode(u);
  142. int mid=(tr[u].l+tr[u].r)>>1;
  143. if(x<=mid) {
  144. return ask_color(tr[u].lson,x);
  145. }
  146. else {
  147. return ask_color(tr[u].rson,x);
  148. }
  149. }
  150. void change_tree(int u,int l,int r,int c) {
  151. if(l==tr[u].l && r==tr[u].r) {
  152. tr[u].sum=1;
  153. tr[u].lazy=1;
  154. tr[u].setcol=c;
  155. tr[u].lcol=tr[u].rcol=c;
  156. return ;
  157. }
  158. pushnode(u);
  159. int mid=(tr[u].l+tr[u].r)>>1;
  160. int ls=tr[u].lson,rs=tr[u].rson;
  161. if(r<=mid) {
  162. change_tree(ls,l,r,c);
  163. }
  164. else if(l>mid) {
  165. change_tree(rs,l,r,c);
  166. }
  167. else {
  168. change_tree(ls,l,mid,c);
  169. change_tree(rs,mid+1,r,c);
  170. }
  171. update(u);
  172. }
  173. int query(int a,int b) {
  174. int res=0;
  175. while(belong[a]!=belong[b]) {
  176. if(dep[top[belong[a]]]<dep[top[belong[b]]]) swap(a,b);
  177. int l=fa[top[belong[a]]];
  178. int z=lroot[belong[a]];
  179. res+=query_tree(z,1,rnk[a]);
  180. if(tr[z].lcol==ask_color(lroot[belong[l]],rnk[l])) {
  181. --res;
  182. }
  183. a=l;
  184. }
  185. if(rnk[a]>rnk[b]) swap(a,b);
  186. res+=query_tree(lroot[belong[a]],rnk[a],rnk[b]);
  187. return res;
  188. }
  189. void change(int a,int b,int c) {
  190. while(belong[a]!=belong[b]) {
  191. if(dep[top[belong[a]]]<dep[top[belong[b]]]) swap(a,b);
  192. int z=lroot[belong[a]];
  193. int l=fa[top[belong[a]]];
  194. change_tree(z,1,rnk[a],c);
  195. a=l;
  196. }
  197. if(rnk[a]>rnk[b]) swap(a,b);
  198. change_tree(lroot[belong[a]],rnk[a],rnk[b],c);
  199. }
  200. void prepare() {
  201. scanf("%d%d",&n,&m);
  202. siji(i,1,n) {
  203. scanf("%d",&col[i]);
  204. }
  205. int u,v;
  206. xiaosiji(i,1,n) {
  207. scanf("%d%d",&u,&v);
  208. addtwo(u,v);
  209. }
  210. dep[1]=1;
  211. dfs1(1);dfs2(1);
  212. }
  213. void solve() {
  214. prepare();
  215. char s[5];
  216. int a,b,c;
  217. siji(i,1,m) {
  218. scanf("%s",s+1);
  219. if(s[1]=='Q') {
  220. scanf("%d%d",&a,&b);
  221. printf("%d\n",query(a,b));
  222. }
  223. else {
  224. scanf("%d%d%d",&a,&b,&c);
  225. change(a,b,c);
  226. }
  227. }
  228. }
  229. int main() {
  230. #ifdef ivorysi
  231. freopen("f1.in","r",stdin);
  232. #endif
  233. solve();
  234. return 0;
  235. }

CC DGCD

All submissions for this problem are available.
You're given a tree on N vertices. Each vertex has a positive integer written on it, number on the ith vertex being vi. Your program must process two types of queries :
1. Find query represented by F u v : Find out gcd of all numbers on the unique path between vertices u and v in the tree (both inclusive).
2. Change query represented by C u v d : Add d to the number written on all vertices along the unique path between vertices u and v in the tree (both inclusive).

Input

First line of input contains an integer N denoting the size of the vertex set of the tree. Then follow N - 1 lines, ith of which contains two integers ai and bi denoting an edge between vertices ai and bi in the tree. After this follow N space separated integers in a single line denoting initial values vi at each of these nodes. Then follows a single integer Q on a line by itself, denoting the number of queries to follow. Then follow Q queries, each one on a line by itself. Each query is either a find query or a change query with format as given in problem statement. Note that all vertices are 0-based.

Output

For every find query, print the answer to that query in one line by itself.

Input:

6
0 4
0 5
1 5
5 2
3 5
3 1 3 2 4 2
5
F 3 5
C 1 3 1
C 3 4 4
F 3 0
F 2 5

Output:

2
7
1

Constraints

1 <= N <= 50000
1 <= Q <= 50000
0 <= u, v <= N-1
1 <= vi <= 10^4
0 <= d <= 10^4

题解

这道题考虑这样一件事



进行累加后



很妙的是,m-k显然没有变啊
所以我们考虑差分,计算所有差分的gcd,然后用第一个数的原值和这个gcd计算gcd即可
这样线段树上的维护只需要单点修改
(如何把一道线段树的题变得非常恶心)
(你只需要一棵树就够了)

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <stack>
  7. #include <cmath>
  8. #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  9. #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  10. #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  11. #define MOD 974711
  12. #define MAXN 100005
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long ll;
  16. struct treenode {
  17. int l,r,
  18. lson,
  19. rson,
  20. val,
  21. sum;
  22. bool lazy;
  23. }tr[MAXN*10];
  24. int treecnt;
  25. int gcd(int a,int b) {
  26. return b==0 ? a:gcd(b,a%b);
  27. }
  28. void update(int u) {
  29. int ls=tr[u].lson,rs=tr[u].rson;
  30. tr[u].val=gcd(abs(tr[ls].val),abs(tr[rs].val));
  31. tr[u].sum=tr[ls].sum+tr[rs].sum;
  32. }
  33. int dep[MAXN],
  34. fa[MAXN],
  35. size[MAXN],
  36. son[MAXN],
  37. rnk[MAXN],
  38. belong[MAXN],
  39. top[MAXN],
  40. linkcnt,
  41. lroot[MAXN];
  42. int n,num[MAXN],m;
  43. struct node {
  44. int to,next;
  45. }edge[MAXN*2];
  46. int head[MAXN],sumedge;
  47. void add(int u,int v) {
  48. edge[++sumedge].to=v;
  49. edge[sumedge].next=head[u];
  50. head[u]=sumedge;
  51. }
  52. void addtwo(int u,int v) {
  53. add(u,v);
  54. add(v,u);
  55. }
  56. void dfs1(int u){
  57. size[u]=1;
  58. for(int i=head[u];i;i=edge[i].next) {
  59. int v=edge[i].to;
  60. if(v!=fa[u]) {
  61. fa[v]=u;
  62. dep[v]=dep[u]+1;
  63. dfs1(v);
  64. size[u]+=size[v];
  65. if(size[v]>size[son[u]]) son[u]=v;
  66. }
  67. }
  68. }
  69. void build(int u,int l,int r);
  70. vector<int> line;
  71. void dfs2(int u) {
  72. if(!belong[u]) {
  73. belong[u]=++linkcnt;
  74. top[belong[u]]=u;
  75. rnk[u]=1;
  76. line.push_back(0);
  77. }
  78. line.push_back(u);
  79. if(!son[u]) {
  80. lroot[belong[u]]=++treecnt;
  81. build(treecnt,1,rnk[u]);
  82. line.clear();
  83. return;
  84. }
  85. belong[son[u]]=belong[u];
  86. rnk[son[u]]=rnk[u]+1;
  87. dfs2(son[u]);
  88. for(int i=head[u];i;i=edge[i].next) {
  89. int v=edge[i].to;
  90. if(v!=son[u] && v!=fa[u]) {
  91. dfs2(v);
  92. }
  93. }
  94. }
  95. void build(int u,int l,int r) {
  96. tr[u].l=l;tr[u].r=r;
  97. if(l==r) {
  98. tr[u].sum=1;
  99. tr[u].val=num[line[l]]-num[line[l-1]];
  100. tr[u].sum=num[line[l]]-num[line[l-1]];
  101. return;
  102. }
  103. int mid=(l+r)>>1;
  104. tr[u].lson=++treecnt;tr[u].rson=++treecnt;
  105. build(tr[u].lson,l,mid);
  106. build(tr[u].rson,mid+1,r);
  107. update(u);
  108. }
  109. int query_tree(int u,int l,int r) {
  110. if(tr[u].l==l && tr[u].r==r) {
  111. return abs(tr[u].val);
  112. }
  113. int ls=tr[u].lson,rs=tr[u].rson;
  114. int mid=(tr[u].l+tr[u].r)>>1;
  115. if(r<=mid) {
  116. return query_tree(ls,l,r);
  117. }
  118. else if(l>mid) {
  119. return query_tree(rs,l,r);
  120. }
  121. else {
  122. return gcd(query_tree(ls,l,mid),query_tree(rs,mid+1,r));
  123. }
  124. }
  125. int get_sum(int u,int l,int r) {
  126. if(tr[u].l==l && tr[u].r==r) {
  127. return tr[u].sum;
  128. }
  129. int ls=tr[u].lson,rs=tr[u].rson;
  130. int mid=(tr[u].l+tr[u].r)>>1;
  131. if(r<=mid) {
  132. return get_sum(ls,l,r);
  133. }
  134. else if(l>mid) {
  135. return get_sum(rs,l,r);
  136. }
  137. else {
  138. return get_sum(ls,l,mid)+get_sum(rs,mid+1,r);
  139. }
  140. }
  141. void change_tree_pos(int u,int x,int d) {
  142. if(tr[u].l==tr[u].r) {
  143. tr[u].sum+=d;
  144. tr[u].val+=d;
  145. return;
  146. }
  147. int mid=(tr[u].l+tr[u].r)>>1;
  148. int ls=tr[u].lson,rs=tr[u].rson;
  149. if(x<=mid) {
  150. change_tree_pos(ls,x,d);
  151. }
  152. else {
  153. change_tree_pos(rs,x,d);
  154. }
  155. update(u);
  156. }
  157. int query(int a,int b) {
  158. int res=0;
  159. while(belong[a]!=belong[b]) {
  160. if(dep[top[belong[a]]]<dep[top[belong[b]]]) swap(a,b);
  161. int l=top[belong[a]],z=lroot[belong[a]];
  162. res=gcd(res,query_tree(z,1,rnk[a]));
  163. a=fa[l];
  164. }
  165. if(rnk[a]>rnk[b]) swap(a,b);
  166. int z=lroot[belong[a]];
  167. int l=get_sum(z,1,rnk[a]);
  168. if(rnk[a]==rnk[b]) res=gcd(res,l);
  169. else {
  170. l=gcd(l,query_tree(z,rnk[a]+1,rnk[b]));
  171. res=gcd(res,l);
  172. }
  173. return res;
  174. }
  175. void change(int a,int b,int d) {
  176. while(belong[a]!=belong[b]) {
  177. if(dep[top[belong[a]]]<dep[top[belong[b]]]) swap(a,b);
  178. int l=top[belong[a]],z=lroot[belong[a]];
  179. change_tree_pos(z,1,d);
  180. if(rnk[a]+1<=tr[z].r) {
  181. change_tree_pos(z,rnk[a]+1,-d);
  182. }
  183. a=fa[l];
  184. }
  185. if(rnk[a]>rnk[b]) swap(a,b);
  186. int z=lroot[belong[a]];
  187. change_tree_pos(z,rnk[a],d);
  188. if(rnk[b]+1<=tr[z].r) {
  189. change_tree_pos(z,rnk[b]+1,-d);
  190. }
  191. }
  192. void prepare() {
  193. scanf("%d",&n);
  194. int u,v;
  195. xiaosiji(i,1,n) {
  196. scanf("%d%d",&u,&v);
  197. ++u;++v;
  198. addtwo(u,v);
  199. }
  200. siji(i,1,n) {
  201. scanf("%d",&num[i]);
  202. }
  203. dep[1]=1;
  204. dfs1(1);dfs2(1);
  205. }
  206. void solve() {
  207. prepare();
  208. scanf("%d",&m);
  209. char s[5];
  210. int a,b,d;
  211. siji(i,1,m) {
  212. scanf("%s",s+1);
  213. if(s[1]=='F') {
  214. scanf("%d%d",&a,&b);
  215. ++a,++b;
  216. printf("%d\n",query(a,b));
  217. }
  218. else {
  219. scanf("%d%d%d",&a,&b,&d);
  220. ++a,++b;
  221. change(a,b,d);
  222. }
  223. }
  224. }
  225. int main() {
  226. #ifdef ivorysi
  227. freopen("f1.in","r",stdin);
  228. #endif
  229. solve();
  230. return 0;
  231. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注