[关闭]
@ivorysi 2018-01-02T12:00:47.000000Z 字数 29882 阅读 676

数据结构3学习笔记

笔记


替罪羊树套主席树

带插入询问区间第k小

题目大意:

给定一个初始长度为 n 的序列,现在有 q 次操作,操作有三种:1.询问区间 [l,r] 内的第 k 小值。2.修改一个位置 i 上的数ai变成 x 。3.在从左往右第 x 个位置后插入一个新的元素,值为 y 。强制在线。
值域在[0,70000]

题解

总结一下
内层是一个主席树,节点都要动态开,满足加入一个数,删除一个主席树(意思是删除这条主席树新创造出来的个节点)如果这个主席树的点被别人用了,就不删除它,所以每个点还要维护一下在几棵树里
还要满足合并……debug了那么久就是合并抄错了,建一个新树,这个新的节点的sum是用来合并的两棵树的加和

外层是一个替罪羊树,替罪羊树由于不用旋转可以比较快的维护
要满足暴力重建(拍扁重建233),修改(将沿路的节点减去旧值加上新值一样,主席树的删除和增加),插入(沿路在主席树里加上新值,然后找这条路径上最高的不满足平衡条件的点,暴力重建),询问(找到一些主席树的根节点和一些单个节点值,每层节点个数不超过4个,外层二分答案,所以询问一次

代码

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <iostream>
  4. //#define ivorysi
  5. using namespace std;
  6. const int V = 70000,N=72000;
  7. const double alphaS = 0.75;
  8. struct node {
  9. node *lc,*rc;
  10. int sum,cnt;
  11. }*null,pool[10000005],*tail = pool,*rec[10000005];
  12. int top;
  13. node *getnull() {
  14. node *res = tail++;
  15. res->sum = 0;
  16. res->lc = res->rc = res;
  17. res->cnt = 1;
  18. return res;
  19. }
  20. node *Newnode() {
  21. node *res;
  22. if(top!=0) res = rec[top--];
  23. else res = tail++;
  24. res->lc = res->rc = null;
  25. res->cnt = 1;
  26. return res;
  27. }
  28. void del(node *&p) {
  29. if(p && !--p->cnt) {
  30. rec[++top] = p;
  31. del(p->lc);
  32. del(p->rc);
  33. p = NULL;
  34. }
  35. }
  36. node* add(node *x,const int &l,const int &r,const int &p,const int &delta) {
  37. if(x->sum + delta == 0) {
  38. ++null->cnt;
  39. return null;
  40. }
  41. node *res = Newnode();
  42. res->sum = x->sum + delta;
  43. res->lc = x->lc; res->rc = x->rc;
  44. ++res->lc->cnt; ++res->rc->cnt;
  45. if(l==r) return res;
  46. int mid = (l + r) >>1;
  47. if(p<=mid) {
  48. --res->lc->cnt;
  49. res->lc = add(x->lc,l,mid,p,delta);
  50. }
  51. else {
  52. --res->rc->cnt;
  53. res->rc = add(x->rc,mid+1,r,p,delta);
  54. }
  55. return res;
  56. }
  57. node *merge(node *x,node *y) {
  58. if(y==null) {
  59. ++x->cnt;
  60. return x;
  61. }
  62. if(x==null) {
  63. ++y->cnt;
  64. return y;
  65. }
  66. node *res=Newnode();
  67. res->lc = merge(x->lc,y->lc);
  68. res->rc = merge(x->rc,y->rc);
  69. res->sum = x->sum + y->sum;
  70. return res;
  71. }
  72. struct scap_node {
  73. node *seg;
  74. scap_node *lc,*rc;
  75. int size,val;
  76. void update() {
  77. node *temp = merge(lc->seg,rc->seg);
  78. seg = add(temp,0,V,val,1);
  79. del(temp);
  80. size = lc->size + rc->size + 1;
  81. }
  82. }*root,*scap_null,scap_pool[N],*scap_tail=scap_pool;
  83. scap_node* getscap_null() {
  84. scap_node *res = scap_tail++;
  85. res->seg = null;
  86. res->lc = res->rc = res;
  87. res->size = res->val = 0;
  88. return res;
  89. }
  90. scap_node* Newscap_node(const int &val) {
  91. scap_node* res = new scap_node;
  92. res->val = val;
  93. res->size = 1;
  94. res->seg = add(null,0,V,val,1);
  95. res->lc = res->rc = scap_null;
  96. return res;
  97. }
  98. scap_node* flatten(scap_node *x,scap_node *y) {
  99. if(x == scap_null) return y;
  100. del(x->seg);
  101. x->rc = flatten(x->rc,y);
  102. return flatten(x->lc,x);
  103. }
  104. scap_node* build(scap_node *x,const int &n) {
  105. if(n==0) {
  106. x->lc = scap_null;
  107. return x;
  108. }
  109. scap_node *y = build(x,n>>1);
  110. scap_node *z = build(y->rc,n - 1 - (n>>1));
  111. y->rc = z->lc;
  112. z->lc = y;
  113. y->update();
  114. return z;
  115. }
  116. scap_node* reBuild(scap_node *x) {
  117. int n = x->size;
  118. scap_node t;
  119. t.lc=t.rc=NULL;
  120. scap_node *head = flatten(x,&t);
  121. build(head,n);
  122. return t.lc;
  123. }
  124. int Modify(scap_node *x,const int &p,const int &val) {
  125. int now = x->lc->size + 1,res;
  126. if(p < now) res = Modify(x->lc,p,val);
  127. else if(p > now) res = Modify(x->rc,p-now,val);
  128. else res = x->val , x->val = val;
  129. node *temp = x->seg;
  130. x->seg = add(temp,0,V,res,-1);
  131. del(temp);
  132. temp = x->seg;
  133. x->seg = add(temp,0,V,val,1);
  134. del(temp);
  135. return res;
  136. }
  137. scap_node *flag,**fa;
  138. void Insert(scap_node *&x,const int &p,const int &val) {
  139. if(x == scap_null) {
  140. x = Newscap_node(val);
  141. return ;
  142. }
  143. ++x->size;
  144. node *temp = x->seg;
  145. x->seg = add(temp,0,V,val,1);
  146. del(temp);
  147. int now = x->lc->size + 1;
  148. p<=now ? Insert(x->lc,p,val) : Insert(x->rc,p-now,val);
  149. int S = alphaS * x->size;
  150. if(x->lc->size > S || x->rc->size > S) {
  151. flag=x;
  152. fa=NULL;
  153. }
  154. if(x->lc == flag) fa = &x->lc;
  155. else if(x->rc == flag) fa = &x->rc;
  156. }
  157. int a[N],lenA,lenB;
  158. node *b[N];
  159. void Query(scap_node *x,int l,int r) {
  160. if(x == scap_null) return;
  161. if(l == 1 && r== x->size) {
  162. b[++lenB] = x->seg;
  163. return ;
  164. }
  165. int mid = x->lc->size + 1;
  166. if(l <= mid && r >= mid) a[++lenA] = x->val;
  167. if(r == mid) --r;
  168. if(l == mid) ++l;
  169. if(r < l) return ;
  170. if(r < mid) Query(x->lc,l,r);
  171. else if(l > mid) Query(x->rc,l-mid,r-mid);
  172. else {
  173. Query(x->lc,l,mid-1);
  174. Query(x->rc,1,r-mid);
  175. }
  176. }
  177. int Solve(const int &l,const int &r,int k) {
  178. lenA = 0,lenB = 0;
  179. Query(root,l,r);
  180. int L = 0,R = V;
  181. while(L < R) {
  182. int mid = (L+R)>>1;
  183. int sum = 0;
  184. for (int i = 1 ;i <= lenA ; ++i) {
  185. if(a[i] >= L && a[i] <= mid) ++sum;
  186. }
  187. for (int i = 1 ;i <= lenB ; ++i) {
  188. sum += b[i]->lc->sum;
  189. }
  190. if(sum >= k) {
  191. for(int i = 1;i <= lenB;++i) {
  192. b[i] = b[i]->lc;
  193. }
  194. R = mid;
  195. }
  196. else {
  197. k-=sum;
  198. for(int i = 1;i <= lenB;++i) {
  199. b[i] = b[i]->rc;
  200. }
  201. L = mid+1;
  202. }
  203. }
  204. return R;
  205. }
  206. scap_node* Init(int l,int r) {
  207. if(r < l) return scap_null;
  208. int mid = (l + r)>>1;
  209. scap_node *res = Newscap_node(a[mid]);
  210. res->lc = Init(l,mid-1);
  211. res->rc = Init(mid+1,r);
  212. res->update();
  213. return res;
  214. }
  215. int n,Q;
  216. char op[5];
  217. void dfs(scap_node *u) {
  218. if(u==scap_null) return;
  219. dfs(u->lc);
  220. printf("%d ",u->val);
  221. dfs(u->rc);
  222. }
  223. int main() {
  224. #ifdef ivorysi
  225. freopen("f1.in","r",stdin);
  226. #endif
  227. null = getnull();
  228. scap_null = getscap_null();
  229. scanf("%d",&n);
  230. for(int i = 1;i <= n;++i) {
  231. scanf("%d",&a[i]);
  232. }
  233. root = Init(1,n);
  234. int lastans=0;
  235. int x,y,k;
  236. scanf("%d",&Q);
  237. while(Q--) {
  238. scanf("%s",op+1);
  239. scanf("%d%d",&x,&y);
  240. if(op[1] == 'Q') {
  241. scanf("%d",&k);
  242. x^=lastans;y^=lastans;k^=lastans;
  243. printf("%d\n",lastans = Solve(x,y,k));
  244. }
  245. else if(op[1] == 'M') {
  246. x^=lastans;y^=lastans;
  247. Modify(root,x,y);
  248. }
  249. else {
  250. flag = scap_null;
  251. fa=NULL;
  252. x^=lastans;y^=lastans;
  253. Insert(root,x,y);
  254. if(flag != scap_null) {
  255. flag = reBuild(flag);
  256. if(fa != NULL) *fa = flag;
  257. else root = flag;
  258. }
  259. }
  260. }
  261. }

UOJ #55. 【WC2014】紫荆花之恋

强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。
仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点,每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i都有一个感受能力值 ri,小精灵 i,j成为朋友当且仅当在树上 i和 j的距离 dist(i,j)≤ri+rjdist(i,j)≤ri+rj,其中 dist(i,j)dist(i,j) 表示在这个树上从 i到 j 的唯一路径上所有边的边权和。
强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。
我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇,你必须在他每次出现新结点后马上给出总共的朋友对数,不能拖延哦。

输入格式

第一行包含一个整数,表示测试点编号。
第二行包含一个正整数 n,表示总共要加入的节点数。
我们令加入节点前的总共朋友对数是 last_ans,在一开始时它的值为 0。
接下来 n 行中第 i 行有三个非负整数 ai,ci,ri,表示结点 i的父节点的编号为 ai xor(last_ans mod 10^9)(其中 xor 表示异或,mod表示取余,数据保证这样操作后得到的结果介于 1 到 i−1 之间),与父结点之间的边权为 ci,节点 i 上小精灵的感受能力值为 ri。
注意 a1=c1=0,表示 11 号节点是根结点,对于 i>1,父节点的编号至少为 1。

输出格式

包含 n 行,每行输出 1 个整数,表示加入第 i 个点之后,树上有几对朋友。

样例一

input

0
5
0 0 6
1 2 4
0 9 4
0 5 5
0 2 4

output

0
1
2
4
7

样例二

见样例数据下载。
限制与约定
对于所有数据,满足 1≤ci≤10000,ai≤2×10^9,ri≤10^9。

题解

这道题和替罪羊树的关系并不大,这个东西就是借用了替罪羊树的思想
如果树一开始是给定的,那么我们可以点分治
那么点分治在路上形成的一些树,就是我们对每个节点用作计算的树,由于每次拿的都是重心,所以每个节点所在的树不会超过
我们新加入一个节点,就在它所在的每棵树里加上它,如果某棵树失去了平衡,我们对它暴力重新分治

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <vector>
  5. //#define ivorysi
  6. #define PII pair<int,int>
  7. #define FI first
  8. #define SE second
  9. typedef long long ll;
  10. typedef unsigned int u32;
  11. using namespace std;
  12. const int N = 1e5 + 5 , mod = 1e9;
  13. const double alphaS = 0.777666;
  14. struct data {
  15. int to,next,val;
  16. }edge[N*2];
  17. int head[N],sumedge;
  18. int dist[N],size[N],son[N],fa[N];
  19. int n,test_num,R[N];
  20. int que[N],q_n;
  21. bool vis[N];
  22. ll last_ans;
  23. vector<PII> anc[N];
  24. vector<int> sonS[N];
  25. void add(int u,int v,int c) {
  26. edge[++sumedge].to = v;
  27. edge[sumedge].val = c;
  28. edge[sumedge].next = head[u];
  29. head[u] = sumedge;
  30. }
  31. void addtwo(int u,int v,int c) {
  32. add(u,v,c);add(v,u,c);
  33. }
  34. namespace Treap {
  35. u32 Rand() {
  36. static u32 x = 998666131;
  37. return x += x << 2 | 1;
  38. }
  39. struct node {
  40. u32 pri;
  41. node *lc,*rc;
  42. int val,size;
  43. void Reset(const int &v) {
  44. val = v;
  45. size = 1;
  46. lc = rc = NULL;
  47. pri = Rand();//Treap的魅力在于听天由命
  48. }
  49. void update() {
  50. size = (lc ? lc->size : 0) + 1 + (rc ? rc->size : 0);
  51. }
  52. }pool[4000005],*tail = pool,*rec[4000005],*rt_self[N],*rt_fa[N];
  53. int top = 0;
  54. node *Newnode(const int &v) {
  55. node *res;
  56. if(top!=0) { res = rec[top--];}
  57. else res = tail++;
  58. res->Reset(v);
  59. return res;
  60. }
  61. void del(node *&p) {//内存回收机制
  62. if(!p) return;
  63. rec[++top] = p;
  64. del(p->lc);
  65. del(p->rc);
  66. p = NULL;
  67. }
  68. void Zig(node *&u) {//右旋(左儿子提根)
  69. node *v = u->lc;
  70. u->lc = v->rc;
  71. v->rc = u;
  72. v->size = u->size;
  73. u->update();
  74. u = v;
  75. }
  76. void Zag(node *&u) {//左旋(右儿子提根)
  77. node *v = u->rc;
  78. u->rc = v->lc;
  79. v->lc = u;
  80. v->size = u->size;
  81. u->update();
  82. u = v;
  83. }
  84. void Insert(node *&u,int val) {
  85. if(u == NULL) {
  86. u = Newnode(val);
  87. return ;
  88. }
  89. ++u->size;
  90. if(val <= u->val) {
  91. Insert(u->lc,val);
  92. if(u->lc->pri > u->pri) Zig(u);
  93. }
  94. else {
  95. Insert(u->rc,val);
  96. if(u->rc->pri > u->pri) Zag(u);
  97. }
  98. }
  99. int Qrank(node *u,int val) {
  100. if(!u) return 0;
  101. if(val < u->val) return Qrank(u->lc,val);
  102. else return (u->lc ? u->lc->size : 0) + 1 + Qrank(u->rc,val);
  103. }
  104. }
  105. int calc(const int &st) {//计算重心
  106. que[q_n = 1] = st;
  107. fa[st] = 0;
  108. for(int j = 1 ; j <= q_n ; ++j) {
  109. int u = que[j];
  110. size[u] = 1;son[u] = 0;
  111. for(int i = head[u] ; i ; i = edge[i].next) {
  112. int v = edge[i].to;
  113. if((!vis[v]) && v != fa[u]) {
  114. fa[v] = u;
  115. que[++q_n] = v;
  116. }
  117. }
  118. }
  119. int grav = -1,maxval = 0x3f3f3f3f;
  120. for(int i = q_n;i >= 1 ; --i) {
  121. int u = que[i];
  122. size[fa[u]] += size[u];
  123. if(size[u] > son[fa[u]]) son[fa[u]] = size[u];
  124. if(son[u] < q_n - size[u]) son[u] = q_n - size[u];
  125. if(maxval > son[u] || grav == -1) {
  126. grav = u;
  127. maxval = son[u];
  128. }
  129. }
  130. size[0] = 0;son[0] = 0;
  131. return grav;
  132. }
  133. void divide_and_conquer(const int &u,const int &fa_u) {
  134. int grav = calc(u);
  135. que[q_n = 1] = grav;
  136. vis[grav] = true;dist[grav] = 0;
  137. fa[grav] = 0;
  138. for(int j = 1 ; j <= q_n ; ++j) {
  139. int u = que[j];
  140. for(int i = head[u] ; i ; i = edge[i].next) {
  141. int v = edge[i].to;
  142. if((!vis[v]) && v != fa[u]) {
  143. fa[v] = u;
  144. que[++q_n] = v;
  145. dist[v] = dist[u] + edge[i].val;
  146. }
  147. }
  148. }
  149. for(int i = 1 ; i <= q_n ; ++i) {
  150. int u = que[i];
  151. anc[u].push_back(make_pair(grav,dist[u]));
  152. sonS[grav].push_back(u);
  153. Treap::Insert(Treap::rt_self[grav],dist[u] - R[u]);
  154. if(fa_u != 0) {
  155. Treap::Insert(Treap::rt_fa[grav],anc[u][anc[u].size() - 2].SE - R[u]);
  156. }
  157. }
  158. for(int i = head[grav] ; i ; i = edge[i].next) {
  159. int v = edge[i].to;
  160. if(!vis[v]) divide_and_conquer(v,grav);
  161. }
  162. }
  163. void ReBuild(const int &u,const int &fa_u) {
  164. vector<int> tmpson = sonS[u];
  165. int sav = anc[fa_u].size();
  166. int s = tmpson.size();
  167. for(int i = 0 ; i < s ; ++i) {
  168. int v = tmpson[i];
  169. vis[v] = false;//将这棵树里所有东西都清空
  170. sonS[v].clear();
  171. anc[v].resize(sav);//只保留每个点在这棵树被分治之前所在点分树的重心
  172. Treap::del(Treap::rt_self[v]);
  173. Treap::del(Treap::rt_fa[v]);
  174. }
  175. divide_and_conquer(u,fa_u);
  176. }
  177. void check(const int &u) {
  178. vis[u] = true;
  179. int s = anc[u].size();
  180. for(int i = 0 ; i < s; ++i) {
  181. Treap::Insert(Treap::rt_self[anc[u][i].FI],anc[u][i].SE - R[u]);
  182. if(i != 0) {
  183. Treap::Insert(Treap::rt_fa[anc[u][i].FI],anc[u][i - 1].SE - R[u]);
  184. }
  185. //rt_fa存的就是这棵树里面的节点的值和的上一棵树的重心的值
  186. //用来去重
  187. }
  188. for(int i = 0 ; i < s - 1; ++i) {
  189. int sze_fa = Treap::rt_self[anc[u][i].FI]->size;
  190. int sze_son = Treap::rt_self[anc[u][i + 1].FI]->size;
  191. if(sze_fa <= 30) break;
  192. if(sze_son > alphaS * sze_fa) {//如果这个儿子过大就暴力重建
  193. ReBuild(anc[u][i].FI,(i ? anc[u][i - 1].FI : 0));
  194. break;
  195. }
  196. }
  197. }
  198. int calc_ans(const int &u,const int &v,const int &w) {
  199. int res = 0;
  200. anc[u] = anc[v];
  201. anc[u].push_back(make_pair(u,-w));
  202. int s = anc[u].size();
  203. for(int i = 0 ; i < s ; ++i) {
  204. anc[u][i].SE += w;
  205. sonS[anc[u][i].FI].push_back(u);
  206. res += Treap::Qrank(Treap::rt_self[anc[u][i].FI],R[u] - anc[u][i].SE);
  207. //加上这棵树中新增加的路径条数
  208. if(i != 0) {
  209. res -= Treap::Qrank(Treap::rt_fa[anc[u][i].FI],R[u] - anc[u][i - 1].SE);
  210. //减去前一棵树不合法的路径条数(起点和终点在同一棵子树)
  211. }
  212. }
  213. return res;
  214. }
  215. int main(int argc, char const *argv[]) {
  216. #ifdef ivorysi
  217. freopen("f1.in","r",stdin);
  218. #endif
  219. scanf("%d",&test_num);
  220. scanf("%d",&n);
  221. last_ans = 0;
  222. int fa_i,c;
  223. /*
  224. 树分治中,要求每条路径都经过重心,那么我们可以把距离设成距离重心的距离
  225. dist[u] + dist[v] <= R[u] + R[v]
  226. dist[u] - R[u] <= R[v] - dist[v]
  227. 那么新加入一个点,就把这个点的R[v] - dist[v]加入,查找以重心为根的这棵树里
  228. 比它小或等于它的有多少个
  229. */
  230. for(int i = 1; i <= n; ++i) {
  231. scanf("%d%d%d",&fa_i,&c,&R[i]);
  232. fa_i ^= (last_ans % mod);
  233. if(i == 1) {
  234. anc[i].push_back(make_pair(i,0));
  235. //anc序列里记录的是:重心 这个点到重心的距离,从一开始分治到最后的树的序列
  236. sonS[i].push_back(i);
  237. //sonS[u]是以u为根的点分治树都有哪些节点
  238. Treap::Insert(Treap::rt_self[i],0 - R[i]);
  239. //rt_self[u]是u当根的时候dist[u] - R[u]的取值
  240. puts("0");
  241. vis[1] = 1;
  242. //忘记给1打上标记了……GG,这样会让某个1的儿子多更新很多东西,从而让vector申请的空间超限
  243. continue;
  244. }
  245. addtwo(fa_i,i,c);
  246. last_ans += calc_ans(i,fa_i,c);
  247. check(i);
  248. printf("%lld\n",last_ans);
  249. }
  250. }
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cmath>
  5. #define MAXN 100005
  6. struct node {
  7. int to,next;
  8. }edge[MAXN*2];
  9. int head[MAXN],sumedge;
  10. void add(int u,int v) {
  11. edge[++sumedge].to = v;
  12. edge[sumedge].next = head[u];
  13. head[u] = sumedge;
  14. }
  15. void addtwo(int u,int v) {
  16. add(u,v);add(v,u);
  17. }
  18. struct data {
  19. int lc,rc;
  20. ll sum,tagA,tagB;
  21. }tr[MAXN*20];
  22. int nodecnt;
  23. int n,m,top[MAXN],seq,son[MAXN],fa[MAXN],size[MAXN],que[MAXN],q_n,pos[MAXN];
  24. int cur_time,last[MAXN],times,rt[MAXN],tot;
  25. ll lastans = 0;
  26. void Bfs() {
  27. que[q_n = 1] = 1;
  28. for(int i = 1 ; i <= q_n ; ++i) {
  29. int u = que[i];
  30. size[u] = 1;son[u] = 0;
  31. for(int j = head[u] ; j ; j = edge[j].next) {
  32. int v = edge[j].to;
  33. if(v != fa[u]) {
  34. fa[v] = u;
  35. que[++q_n] = v;
  36. }
  37. }
  38. }
  39. for(int i = q_n ; i >= 2 ; --i) {
  40. int u = que[i];
  41. size[fa[u]] += size[u];
  42. if(size[u] > size[son[fa[u]]]) son[fa[u]] = u;
  43. }
  44. for(int i = 1 ; i <= q_n ; ++i) {
  45. int u = que[i];
  46. if(!top[u]) {
  47. for(int y = u ; y ; y = son[y]) {
  48. top[y] = u;
  49. pos[y] = ++seq;
  50. }
  51. }
  52. }
  53. }
  54. int getlen(int x,int y) {
  55. int res = 0;
  56. while(top[x] != top[y]) {
  57. if(dep[top[x]] < dep[top[y]]) swap(x,y);
  58. res += dep[x] - dep[top[x]] + 1;
  59. x = fa[top[x]];
  60. }
  61. if(dep[x] < dep[y]) swap(x,y);
  62. res += dep[x] - dep[y] + 1;
  63. return res;
  64. }
  65. ll calc(ll a,ll d,int n) {
  66. return a * n + n * (n - 1) / 2 * d;
  67. }
  68. void Modify(int &k,int &k1,int l,int r,int x,int y,const ll &A,const ll &B) {
  69. k = ++nodecnt;
  70. tr[k].tagA = tr[k1].tagA;
  71. tr[k].tagB = tr[k1].tagB;
  72. if(l == x && r == y) {
  73. tr[k].tagA += A;
  74. tr[k].tagB += B;
  75. tr[k].sum = tr[k1].sum + calc(A,B,r - l + 1);
  76. tr[k].lc = tr[k1].lc;tr[k].rc = tr[k1].rc;
  77. return ;
  78. }
  79. int mid = (l + r) >> 1;
  80. if(y <= mid) {
  81. tr[k].rc = tr[k1].rc;
  82. Modify(tr[k].lc,tr[k1].lc,l,mid,x,y,A,B);
  83. }
  84. else if(x > mid) {
  85. tr[k].lc = tr[k1].lc;
  86. Modify(tr[k].rc,tr[k1].rc,mid+1,r,x,y,A,B);
  87. }
  88. else {
  89. Modify(tr[k].lc,tr[k1].lc,l,mid,x,mid,A,B);
  90. Modify(tr[k].rc,tr[k1].rc,mid+1,r,mid+1,y,A + (mid - x + 1) * B,B);
  91. }
  92. tr[k].sum = tr[tr[k].lc].sum + tr[tr[k].rc].sum;
  93. }
  94. void PathModify(int x,int y,ll A,ll B) {
  95. int len = getlen(x,y);
  96. while(top[x] != top[y]) {
  97. if(dep[top[x]] > dep[top[y]]) {
  98. Modify(rt[++tot],rt[cur_time],1,n,
  99. pos[top[x]],pos[x],A + B * (dep[x] - dep[top[x]]),-B);
  100. len -= dep[x] - dep[top[x]] + 1;
  101. A += B * (dep[x] - dep[top[x]] + 1);
  102. x = fa[top[x]];
  103. cur_time = tot;
  104. }
  105. else {
  106. Modify(rt[++tot],rt[cur_time],1,n,pos[top[y]],pos[y],
  107. A + B * (len - (dep[y] - dep[top[y]] + 1)),B);
  108. len -= dep[y] - dep[top[y]] + 1;
  109. y = fa[top[y]];
  110. cur_time = tot;
  111. }
  112. }
  113. if(dep[x] > dep[y]) {
  114. Modify(rt[++tot],rt[cur_time],1,n,pos[y],pos[x],A + B * (dep[x] - dep[y]),-B);
  115. }
  116. else {
  117. Modify(rt[++tot],rt[cur_time],1,n,pos[x],pos[y],A,B);
  118. }
  119. cur_time = tot;
  120. }
  121. ll Query(int k,int l,int r,int x,int y,const ll &A,const ll &B) {
  122. if(l == x && r == y) {
  123. return tr[k].sum + calc(A,B,r - l + 1);
  124. }
  125. int mid = (l + r) >> 1;
  126. if(y <= mid) {
  127. return Query(tr[k].lc,l,mid,x,y,A + tr[k].tagA + tr[k].tagB * (x - l),B + tr[k].tagB);
  128. }
  129. else if(x > mid) {
  130. return Query(tr[k].rc,mid + 1,r,x,y,
  131. A + tr[k].tagA + tr[k].tagB * (x - l),B + tr[k].tagB);
  132. }
  133. else {
  134. return Query(tr[k].lc,l,mid,x,mid,
  135. A + tr[k].tagA + tr[k].tagB * (x - l),B + tr[k].tagB) +
  136. Query(tr[k].rc,mid + 1,r,mid + 1,y,
  137. A + tr[k].tagA * (mid - l + 1),B + tr[k].tagB);
  138. }
  139. }
  140. ll PathQuery(int x,int y) {
  141. }
  142. int main() {
  143. #ifdef ivorysi
  144. freopen("f1.in","r",stdin);
  145. #endif
  146. scanf("%d",&n);
  147. int u,v;
  148. for(int i = 1 ; i < n ; ++i) {
  149. scanf("%d%d",&u,&v);
  150. addtwo(u,v);
  151. }
  152. Bfs();
  153. while(m--) {
  154. }
  155. return 0;
  156. }

Observing the Tree Problem Code: QUERY

All submissions for this problem are available.
Chef gives you a tree, consisting of N nodes. The nodes are numbered from 1 to N, and each node has an integer, which is equal to 0 initially. Then, Chef asks you to perform M queries.
The first type of queries is changing: here, you are given integers X, Y, A and B. Add A to the integer, associated with the node X, then add A+B to the integer, associated with the second node on the way from X to Y, then add A+2*B to the integer, associated with the third node on the way from X to Y, and so on. As you know, there is only one simple path from X to Y.
The second type of queries is a question: here, you are given integers X and Y. Output the sum of all integers, associated with nodes on the way from X to Y.
The third type of queries is a rollback: here, you are given an integer X. All the integers associated with the nodes return to the state after the X-th changing query. If X is 0, then all of them become equal to zero, as in the very beginning.

Input

The first line of an input consists of two integers - N and M.
Then, N−1 lines follow. These N−1 lines describe the tree structure. Each line consists of two integers - X and Y, and that means that there is an edge between node X and node Y.
Then, M lines follow. A single line denotes a single query, which has one of the following forms: (See the sample for the detailed explanation)
c X1 Y1 A B - changing query,
q X1 Y1 - question query,
l X1 - rollback query.
As you can see, the numbers X and Y aren't given to you directly. For the rollback query, actual number X will be equal to (X1+lastans) modulo (total number of changing queries before this query + 1). For the changing and question queries, X will be equal to ((X1+lastans) modulo N)+1 and Y will be equal to ((Y1+lastans) modulo N)+1, where lastans denotes the last number that you have output, or zero if you haven't output any numbers yet.

Output

For each question query output the answer on a single line.

Constraints

1 ≤ N, M ≤ 100000 (105)
0 ≤ A, B ≤ 1000
0 ≤ X1, Y1 ≤ 100000 (105)

Example

Input:

5 7
1 2
2 3
3 4
4 5
c 1 4 2 3
c 2 3 5 10
q 1 3
l 1
q 1 3
l 1
q 1 3

Output:

35
0
15

Explanation

As you can see, the tree in the sample is like a line. Let's denote the first state of integers 0 0 0 0 0, where the i-th integer means the integer associated with the node i.
In the first changing query "c 1 4 2 3", the actual numbers are X = (1 + 0) modulo 5 + 1 = 2, Y = (4 + 0) modulo 5 + 1 = 5. Hence the state will be 0 2 5 8 11 after this query.
After the second changing query "c 2 3 5 10", the state will be 0 2 10 23 11 for similar reason.
In the next question query, the actual numbers are X = (1 + 0) modulo 5 + 1 = 2, Y = (3 + 0) modulo 5 + 1 = 4. Hence the answer must be 2 + 10 + 23 = 35.
In the first rollback query "l 1", the actual number is X = (1 + 35) modulo (2 + 1) = 36 modulo 3 = 0, since lastans = 36. Thus the state will be rollbacked to 0 0 0 0 0.
Then the answer of the next question query "q 1 3" must be 0, because all integers are currently 0.
In the second rollback query "l 1", the actual number is X = (1 + 0) modulo (2 + 1) = 1, since lastans = 0. Thus the state will be 0 2 5 8 11, which is the state after the first changing query.
Then the answer of the last question query must be 2 + 5 + 8 = 15.

题解

给出一棵树,要求维护一下三种操作
c x y a b 表示在x到y的路径上增加一个等差数列,首项为a公差为b
q x y表示x到y路径上的点权和
l x表示回到某一次修改后版本
强制在线

那么这就要用到可持久化了……我们树链剖分得用dfs序来,建一棵大树
每次累加的时候打上标记,经过的区间全都加上等差数列的总和,询问的时候要累加上根节点到询问节点所有标记,修改就是新建节点
好像……就没什么了???
然而这道题教会我的更多……我都学会了如何写随机生成一棵树的代码了
这个bug令我头秃

  1. return Query(tr[k].lc,l,mid,x,mid,
  2. A + tr[k].tagA + tr[k].tagB * (x - l),B + tr[k].tagB) +
  3. Query(tr[k].rc,mid + 1,r,mid + 1,y,
  4. A + tr[k].tagA + tr[k].tagB * (mid - l + 1),B + tr[k].tagB);

似乎没什么不对的???

  1. return Query(tr[k].lc,l,mid,x,mid,
  2. A + tr[k].tagA + tr[k].tagB * (x - l),B + tr[k].tagB) +
  3. Query(tr[k].rc,mid + 1,r,mid + 1,y,
  4. A + B * (mid + 1 - l) + tr[k].tagA + tr[k].tagB * (mid - l + 1),B + tr[k].tagB);

实际上原来的A都变成新的啦!!!
因为AB都是维护[x,y]区间的,线段树上区间断两半的时候,A也要更新啊……
本来,我是发现不了这个bug的,然而我觉得这样写有点啰嗦,然后改成了别的写法……结果就……跑过了我的随机数据……结果就A了!!!
然后我才知道query函数错了,苦思冥想才发现原来是这样
代码还是贴清晰易懂一点的吧,函数太长导致分行也太蠢了2333

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cmath>
  5. //#define ivorysi
  6. #define MAXN 200005
  7. using namespace std;
  8. typedef long long ll;
  9. struct node {
  10. int to,next;
  11. }edge[MAXN*2];
  12. int head[MAXN],sumedge;
  13. void add(int u,int v) {
  14. edge[++sumedge].to = v;
  15. edge[sumedge].next = head[u];
  16. head[u] = sumedge;
  17. }
  18. void addtwo(int u,int v) {
  19. add(u,v);add(v,u);
  20. }
  21. struct data {
  22. int lc,rc;
  23. ll sum,tagA,tagB;
  24. }tr[MAXN*300];
  25. int nodecnt;
  26. int n,m,top[MAXN],seq,son[MAXN],fa[MAXN],size[MAXN],que[MAXN],q_n,pos[MAXN],dep[MAXN];
  27. int cur_time,last[MAXN],times,rt[3000005],tot;
  28. ll lastans = 0;
  29. char s;
  30. void Bfs() {
  31. que[q_n = 1] = 1;
  32. dep[1] = 1;
  33. for(int i = 1 ; i <= q_n ; ++i) {
  34. int u = que[i];
  35. size[u] = 1;son[u] = 0;
  36. for(int j = head[u] ; j ; j = edge[j].next) {
  37. int v = edge[j].to;
  38. if(v != fa[u]) {
  39. dep[v] = dep[u] + 1;
  40. fa[v] = u;
  41. que[++q_n] = v;
  42. }
  43. }
  44. }
  45. for(int i = q_n ; i >= 2 ; --i) {
  46. int u = que[i];
  47. size[fa[u]] += size[u];
  48. if(size[u] > size[son[fa[u]]]) son[fa[u]] = u;
  49. }
  50. for(int i = 1 ; i <= q_n ; ++i) {
  51. int u = que[i];
  52. if(!top[u]) {
  53. for(int y = u ; y ; y = son[y]) {
  54. top[y] = u;
  55. pos[y] = ++seq;
  56. }
  57. }
  58. }
  59. }
  60. int getlen(int x,int y) {
  61. int res = 0;
  62. while(top[x] != top[y]) {
  63. if(dep[top[x]] < dep[top[y]]) swap(x,y);
  64. res += dep[x] - dep[top[x]] + 1;
  65. x = fa[top[x]];
  66. }
  67. if(dep[x] < dep[y]) swap(x,y);
  68. res += dep[x] - dep[y] + 1;
  69. return res;
  70. }
  71. ll calc(ll a,ll d,int n) {
  72. return a * n + 1LL * n * (n - 1) / 2 * d;
  73. }
  74. void Modify(int &k,const int &k1,const int &l,const int &r,const int &x,const int &y,const ll &A,const ll &B) {
  75. k = ++nodecnt;
  76. tr[k].tagA = tr[k1].tagA;
  77. tr[k].tagB = tr[k1].tagB;
  78. tr[k].sum = tr[k1].sum + calc(A,B,y - x + 1);
  79. if(l == x && r == y) {
  80. tr[k].tagA += A;
  81. tr[k].tagB += B;
  82. tr[k].lc = tr[k1].lc;tr[k].rc = tr[k1].rc;
  83. return ;
  84. }
  85. int mid = (l + r) >> 1;
  86. if(y <= mid) {
  87. tr[k].rc = tr[k1].rc;
  88. Modify(tr[k].lc,tr[k1].lc,l,mid,x,y,A,B);
  89. }
  90. else if(x > mid) {
  91. tr[k].lc = tr[k1].lc;
  92. Modify(tr[k].rc,tr[k1].rc,mid+1,r,x,y,A,B);
  93. }
  94. else {
  95. Modify(tr[k].lc,tr[k1].lc,l,mid,x,mid,A,B);
  96. Modify(tr[k].rc,tr[k1].rc,mid+1,r,mid+1,y,A + (mid - x + 1) * B,B);
  97. }
  98. }
  99. void PathModify(int x,int y,ll A,ll B) {
  100. int len = getlen(x,y);
  101. while(top[x] != top[y]) {
  102. if(dep[top[x]] > dep[top[y]]) {
  103. Modify(rt[++tot],rt[cur_time],1,n,
  104. pos[top[x]],pos[x],A + B * (dep[x] - dep[top[x]]),-B);
  105. len -= dep[x] - dep[top[x]] + 1;
  106. A += B * (dep[x] - dep[top[x]] + 1);
  107. x = fa[top[x]];
  108. cur_time = tot;
  109. }
  110. else {
  111. Modify(rt[++tot],rt[cur_time],1,n,pos[top[y]],pos[y],
  112. A + B * (len - (dep[y] - dep[top[y]] + 1)),B);
  113. len -= dep[y] - dep[top[y]] + 1;
  114. y = fa[top[y]];
  115. cur_time = tot;
  116. }
  117. }
  118. if(dep[x] > dep[y]) {
  119. Modify(rt[++tot],rt[cur_time],1,n,pos[y],pos[x],A + B * (dep[x] - dep[y]),-B);
  120. }
  121. else {
  122. Modify(rt[++tot],rt[cur_time],1,n,pos[x],pos[y],A,B);
  123. }
  124. cur_time = tot;
  125. }
  126. ll Query(const int &k,const int &l,const int &r,const int &x,const int &y) {
  127. if(l == x && r == y) {
  128. return tr[k].sum;
  129. }
  130. int mid = (l + r) >> 1;
  131. ll res;
  132. if(y <= mid) {
  133. res = Query(tr[k].lc,l,mid,x,y);
  134. }
  135. else if(x > mid) {
  136. res = Query(tr[k].rc,mid + 1,r,x,y);
  137. }
  138. else {
  139. res = Query(tr[k].lc,l,mid,x,mid) + Query(tr[k].rc,mid + 1,r,mid + 1,y);
  140. }
  141. res += calc(tr[k].tagA + tr[k].tagB * (x - l),tr[k].tagB,y - x + 1);
  142. return res;
  143. }
  144. ll PathQuery(int x,int y) {
  145. ll res = 0;
  146. while(top[x] != top[y]) {
  147. if(dep[top[x]] < dep[top[y]]) swap(x,y);
  148. res += Query(rt[cur_time],1,n,pos[top[x]],pos[x]);
  149. x = fa[top[x]];
  150. }
  151. if(dep[x] > dep[y]) swap(x,y);
  152. res += Query(rt[cur_time],1,n,pos[x],pos[y]);
  153. return res;
  154. }
  155. void change(int &x) {
  156. x = (lastans + x) % n + 1;
  157. }
  158. int read() {
  159. char c = getchar();
  160. int res = 0;
  161. while(c < '0' || c > '9') c = getchar();
  162. while(c >= '0' && c <= '9') {
  163. res = res * 10 + c - '0';
  164. c = getchar();
  165. }
  166. return res;
  167. }
  168. void out(ll x) {
  169. if(x >= 10) {
  170. out(x / 10);
  171. }
  172. putchar('0' + x % 10);
  173. }
  174. int main() {
  175. #ifdef ivorysi
  176. freopen("f1.in","r",stdin);
  177. #endif
  178. n = read();m = read();
  179. for(int i = 1 ; i < n ; ++i) {
  180. addtwo(read(),read());
  181. }
  182. Bfs();
  183. int x,y,a,b;
  184. int cnt = 0;
  185. while(m--) {
  186. s = getchar();
  187. while(s < 'a' || s > 'z') s = getchar();
  188. if(s == 'c') {
  189. x = read();y = read();a = read();b = read();
  190. change(x);change(y);
  191. PathModify(x,y,a,b);
  192. last[++times] = cur_time;
  193. }
  194. else if(s == 'q') {
  195. ++cnt;
  196. x = read();y = read();
  197. change(x);change(y);
  198. lastans = PathQuery(x,y);
  199. out(lastans);
  200. putchar('\n');
  201. }
  202. else if(s == 'l'){
  203. x = read();
  204. x = 1LL * (x + lastans) % (times + 1);
  205. cur_time = last[x];
  206. }
  207. }
  208. return 0;
  209. }

为了学可持久化平衡树写的无旋式Treap

题面就是可怕的维修数列啦

无旋式Treap是什么呢,如果,我们欧气满满,给每一个节点赋上一个随机的权值,我们再把它建成一棵树,它的期望高度是
这就是Treap的原理啊,我们反正不知道数据怎么给,我们就随便建啊
那问题就是,如果我非……怎么办啊?不存在的,你非出题人也不知道你到底往那边非啊,如果你正好撞上了出题人想卡的……你就拿你QQ号或者对象生日生成随机数呗,如果被撞了那可能就是迷之绿色
(以上纯属胡扯)

好的我们每个节点还是维护那些破烂东西,我再列举一遍
1.节点的值
2.子树总和
3.子树大小
4.左最大值
5.右最大值
6.最大子段和
7.翻转标记
8.覆盖标记
9.左子树节点指针
10.右子树节点指针
11.随机数

然后这个平衡树需要什么操作呢,就两个
一个是合并两个Treap a b 要求a里面的所有元素都在b前面,返回一棵新的Treap包含a b中的所有元素
一个是分离,传进去一个Treap 返回两个Treap L R,L中包含了原来的Treap前pos个节点,R中是剩余的节点

直接给代码比较快

  1. node* Merge(node *l,node *z) {
  2. if(l == NULL) return z;
  3. if(z == NULL) return l;
  4. if(l->pri > z->pri) {
  5. l->pushdown();
  6. l->rc = Merge(l->rc,z);
  7. l->update();
  8. return l;
  9. }
  10. else {
  11. z->pushdown();
  12. z->lc = Merge(l,z->lc);
  13. z->update();
  14. return z;
  15. }
  16. }
  1. void Split(node *u,node *&L,node *&R,int pos) {
  2. if(u == NULL) {L = R = NULL;return;}
  3. u->pushdown();
  4. if(SZ(u->lc) < pos) {
  5. Split(u->rc,L,R,pos - SZ(u->lc) - 1);
  6. u->rc = NULL; u->update();
  7. L = Merge(u,L);
  8. }
  9. else {
  10. Split(u->lc,L,R,pos);
  11. u->lc = NULL; u->update();
  12. R = Merge(R,u);
  13. }
  14. }

好了这棵树已经完成了!只有短短28行,节点内部的一些烦人的操作相信在splay章节已经经历的差不多了,就不多说了,然后考虑题中的操作。
提取区间的操作是分离原来的树为前pos-1个节点和剩余节点,在从剩余节点中分离出前tot个,不再赘述
1.插入
新建一棵树,二分区间然后不断Merge,然后把树分离前pos和剩余,前pos和新树合并,再和剩余节点合并

2.删除
提取区间,然后合并左右,回收该区间的内存

3.覆盖
提取区间,打上覆盖标记,合并进去

4.翻转
提取区间,打上翻转标记,合并进去

5.总和
提取区间,返回和

6.最大子段和
提取区间,返回维护的最大子段和

(感觉我似乎说了一堆废话)
(写起来还是非常优美的)

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cmath>
  5. //#define ivorysi
  6. #define LX(x) (x != NULL ? x->lmax : -100000)
  7. #define RX(x) (x != NULL ? x->rmax : -100000)
  8. #define SUM(x) (x != NULL ? x->sum : 0)
  9. #define SZ(x) (x != NULL ? x->size : 0)
  10. #define MX(x) (x != NULL ? x->maxnum : -100000)
  11. using namespace std;
  12. typedef long long ll;
  13. typedef unsigned int u32;
  14. u32 Rand() {
  15. static u32 x = 1736382156;
  16. return x += x << 2 | 1;
  17. }
  18. struct node {
  19. node *lc,*rc;
  20. u32 pri;
  21. int size,sum,lmax,rmax,maxnum,val;
  22. int rev,tag;
  23. bool is_cover;
  24. void update() {
  25. size = 1 + SZ(lc) + SZ(rc);
  26. sum = val + SUM(lc) + SUM(rc);
  27. lmax = max( LX(lc) , SUM(lc) + val + max( 0 , LX(rc) ) );
  28. rmax = max( RX(rc) , SUM(rc) + val + max( 0 , RX(lc) ) );
  29. maxnum = max( max( MX(lc) , MX(rc) ) , max( RX(lc) , 0 ) + val + max( LX(rc) , 0) );
  30. }
  31. void Cover(int v) {
  32. sum = v * size;
  33. lmax = rmax = maxnum = max( v , v * size );
  34. val = v;
  35. is_cover = 1;tag = v;
  36. }
  37. void Reverse() {
  38. swap(lc,rc);
  39. swap(lmax,rmax);
  40. rev ^= 1;
  41. }
  42. void pushdown() {
  43. if(is_cover) {
  44. if(lc) lc->Cover(tag);
  45. if(rc) rc->Cover(tag);
  46. is_cover = 0;
  47. }
  48. if(rev) {
  49. if(lc) lc->Reverse();
  50. if(rc) rc->Reverse();
  51. rev = 0;
  52. }
  53. }
  54. }pool[500050],*rec[500050],*tail = pool,*root;
  55. int top;
  56. node *Newnode(int val) {
  57. node *res;
  58. if(top != 0) res = rec[--top];
  59. else res = tail++;
  60. res->lc = res->rc = NULL;
  61. res->size = 1;
  62. res->val = res->lmax = res->rmax = res->sum = res->maxnum = val;
  63. res->rev = res->tag = res->is_cover = 0;
  64. res->pri = Rand();
  65. return res;
  66. }
  67. node* Merge(node *l,node *z) {
  68. if(l == NULL) return z;
  69. if(z == NULL) return l;
  70. if(l->pri > z->pri) {
  71. l->pushdown();
  72. l->rc = Merge(l->rc,z);
  73. l->update();
  74. return l;
  75. }
  76. else {
  77. z->pushdown();
  78. z->lc = Merge(l,z->lc);
  79. z->update();
  80. return z;
  81. }
  82. }
  83. void Split(node *u,node *&L,node *&R,int pos) {
  84. if(u == NULL) {L = R = NULL;return;}
  85. u->pushdown();
  86. if(SZ(u->lc) < pos) {
  87. Split(u->rc,L,R,pos - SZ(u->lc) - 1);
  88. u->rc = NULL; u->update();
  89. L = Merge(u,L);
  90. }
  91. else {
  92. Split(u->lc,L,R,pos);
  93. u->lc = NULL; u->update();
  94. R = Merge(R,u);
  95. }
  96. }
  97. int a[500005],n,m;
  98. char s[30];
  99. node* Build(int l,int r) {
  100. if(l == r) return Newnode(a[l]);
  101. int mid = (l + r) >> 1;
  102. return Merge( Build(l,mid) , Build(mid + 1,r) );
  103. }
  104. void Insert() {
  105. int pos,tot;
  106. scanf("%d%d",&pos,&tot);
  107. for(int i = 1 ; i <= tot ; ++i) {
  108. scanf("%d",&a[i]);
  109. }
  110. node *p = Build(1,tot);
  111. node *L,*R;
  112. Split(root,L,R,pos);
  113. L = Merge(L,p);
  114. root = Merge(L,R);
  115. }
  116. void del(node *&u) {
  117. if(!u) return;
  118. del(u->lc);
  119. del(u->rc);
  120. rec[top++] = u;
  121. u = NULL;
  122. }
  123. void Delete() {
  124. int pos,tot;
  125. scanf("%d%d",&pos,&tot);
  126. node *L,*R,*z,*s;
  127. Split(root,L,R,pos - 1);
  128. Split(R,s,z,tot);
  129. del(s);
  130. root = Merge(L,z);
  131. }
  132. void MAKE_SAME() {
  133. int pos,tot,c;
  134. scanf("%d%d%d",&pos,&tot,&c);
  135. node *L,*R,*s,*z;
  136. Split(root,L,R,pos - 1);
  137. Split(R,s,z,tot);
  138. if(s) s->Cover(c);
  139. L = Merge(L,s);
  140. root = Merge(L,z);
  141. }
  142. void Reverse() {
  143. int pos,tot;
  144. scanf("%d%d",&pos,&tot);
  145. node *L,*R,*s,*z;
  146. Split(root,L,R,pos - 1);
  147. Split(R,s,z,tot);
  148. if(s) s->Reverse();
  149. L = Merge(L,s);
  150. root = Merge(L,z);
  151. }
  152. void Get_Sum() {
  153. int pos,tot;
  154. scanf("%d%d",&pos,&tot);
  155. node *L,*R,*s,*z;
  156. Split(root,L,R,pos - 1);
  157. Split(R,s,z,tot);
  158. printf("%d\n",SUM(s));
  159. L = Merge(L,s);
  160. root = Merge(L,z);
  161. }
  162. void Max_Sum() {
  163. printf("%d\n",root->maxnum);
  164. }
  165. int main() {
  166. #ifdef ivorysi
  167. freopen("f1.in","r",stdin);
  168. #endif
  169. scanf("%d%d",&n,&m);
  170. for(int i = 1 ; i <= n ; ++i) {
  171. scanf("%d",&a[i]);
  172. }
  173. root = Build(1,n);
  174. while(m--) {
  175. scanf("%s",s+1);
  176. if(s[1] == 'I') {
  177. Insert();
  178. }
  179. else if(s[1] == 'D') {
  180. Delete();
  181. }
  182. else if(s[3] == 'K') {
  183. MAKE_SAME();
  184. }
  185. else if(s[1] == 'R') {
  186. Reverse();
  187. }
  188. else if(s[1] == 'G') {
  189. Get_Sum();
  190. }
  191. else {
  192. Max_Sum();
  193. }
  194. }
  195. return 0;
  196. }

CodeChef Queries With Points Problem Code: QPOINT

All submissions for this problem are available.
Read problems statements in Mandarin Chinese and Russian.
Let's solve a realistic problem now! You are given the world map where each country is a polygon on the 2D plane. You may already now that the Global Positioning System can help you to know your current coordinate. So how can you determine which country are you in? That what you need to figure out in this problem. We will give you more detail about input and output description now
There are N countries which are numbered from 1 to N. Each country is represented by a single simple polygon on the 2D plane. Simple polygon means the boundary of the polygon does not cross itself. You should not confuse simple polygon with convex polygon. There are no two countries share a common point.
You have to answer Q queries, each query requires you to find the polygon that contain a specific point. Note that a point on the boundary of the polygon is considered to be inside the polygon. This problem is set in interactive mode that means you need to answer each query right after you read it.

Input

The first line of input contains a single integer N which is the number of countries
The ith line in the next N lines describes the boundary of the ith country. It starts with an integer k and then k pairs of integers (where each pair represent a vextex in 2D) follow. A country's boundary can be drawn by connecting these pairs of vertices in the same order as supplied using straight lines (Finally connect last vertex with first vertex).
The next line contains a single integer Q which is the number of queries.
Each line in the next Q lines contains a pair of integer which is the coordinate in the query.

Output

For each query you print out one number which is the index of the country that contains the query point. Print out -1 if there is no country contains that point.
Attention: the program should clear the output buffer after printing each line. It can be done using fflush(stdout) command or by setting the proper type of buffering at the beginning of the execution - setlinebuf(stdout).

Constraints

1 ≤ N ≤ 100,000
3 ≤ K ≤ 300,000
Sum of all values of K is less than 300,000
1 ≤ Q ≤ 100,000
All coordinates are non-negative integer which are not exceed 109

Example

Input:

2
4 1 4 1 7 7 7 7 4
3 1 1 5 3 7 1
3
2 3
3 6
6 2

Output:

-1
1
2

Explanation

Example case 1. The test case is represented in figure below.
The first country is the rectangle ABCD and the second country is a triangle EFG. Notice that the point J at coordinate (6, 2) is considered to be inside the second country when it is on the boundary of this country

题解

这道题就是可持久化平衡树啦
怎么写呢……我们回忆一下无旋式Treap简单可爱的两个操作
合并两个Treap
我们可以对于两个节点都存在的时候新建一个节点

分离一棵Treap成两个
我们对于两个Treap新建成两个新Treap(虽然有点费空间)

但是由于期望树高是的!!!

所以我们一次就期望新建的节点只有

然后这棵树就被愉快的写完了,我们看一下题吧

有了可持久化平衡树,我们可以离散化x坐标,考虑在每两个x坐标之间如果能存下这个竖条(形象的譬喻)都有哪些边,每两条边之间都是那些国家或者不在国家里面

然而,你存不下???

不,然而你有可持久化平衡树,你可以对每两个x坐标建一个平衡树

然后你对于一个点二分到离某个点最近的线,判断在线的上面是哪

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cmath>
  5. #include <vector>
  6. //#define ivorysi
  7. using namespace std;
  8. typedef long long ll;
  9. typedef unsigned int u32;
  10. const int N = 3e5 + 10;
  11. u32 Rand() {
  12. static u32 x = 1736382156;
  13. return x += x << 2 | 1;
  14. }
  15. struct node {
  16. node *lc,*rc;
  17. u32 pri;
  18. int id;
  19. }pool[20000005],*tail = pool,*rt[N],*nd[N];
  20. struct Point {
  21. ll x,y;
  22. Point() {};
  23. Point(ll _x,ll _y) {
  24. x = _x;y = _y;
  25. }
  26. friend Point operator - (const Point &a,const Point &b) {
  27. return Point(a.x - b.x,a.y - b.y);
  28. }
  29. friend Point operator + (const Point &a,const Point &b) {
  30. return Point(a.x + b.x,a.y + b.y);
  31. }
  32. friend ll operator * (const Point &a,const Point &b) {
  33. return a.x * b.y - a.y * b.x;
  34. }
  35. friend bool operator == (const Point &a,const Point &b) {
  36. return a.x == b.x && a.y == b.y;
  37. }
  38. }p[N];
  39. struct Seg{
  40. Point s,t;
  41. int id,other;
  42. Seg() {}
  43. Seg(Point _s,Point _t,int _id,int _other) {
  44. s = _s; t = _t; id = _id; other = _other;
  45. }
  46. friend bool operator < (const Seg &L,const Seg &Z) {
  47. int minx = min(L.s.x,Z.s.x);
  48. if(minx == L.s.x) {
  49. ll dir = (L.t - L.s) * (Z.s - L.s);
  50. if(dir < 0) return true;
  51. else if(dir > 0) return false;
  52. else {
  53. dir = (L.t - L.s) * (Z.t - L.s);
  54. if(dir < 0) return true;
  55. else return false;
  56. }
  57. }
  58. else {
  59. ll dir = (Z.t - Z.s) * (L.s - Z.s);
  60. if(dir < 0) return false;
  61. else if(dir > 0) return true;
  62. else {
  63. dir = (Z.t - Z.s) * (L.t - Z.s);
  64. if(dir < 0) return false;
  65. else return true;
  66. }
  67. }
  68. }
  69. friend bool operator == (const Seg &a,const Seg &b) {
  70. return a.s == b.s && a.t == b.t;
  71. }
  72. }edge[N];
  73. node *Merge(node *l,node *z) {
  74. if(l == NULL) return z;
  75. if(z == NULL) return l;
  76. node *res = tail++;
  77. if(l->pri > z->pri) {
  78. *res = *l;
  79. res->rc = Merge(l->rc,z);
  80. }
  81. else {
  82. *res = *z;
  83. res->lc = Merge(l,z->lc);
  84. }
  85. return res;
  86. }
  87. void Split(node *u,node *&L,node *&R,Seg &v,int id) {
  88. if(u == NULL) {L = R = NULL;return;}
  89. if(edge[u->id] < v || (edge[u->id] == v && u->id < id)) {
  90. L = tail++;
  91. *L = *u;
  92. Split(u->rc,L->rc,R,v,id);
  93. }
  94. else {
  95. R = tail++;
  96. *R = *u;
  97. Split(u->lc,L,R->lc,v,id);
  98. }
  99. }
  100. void Delete(node *&u,int v) {
  101. node *L,*R,*s,*z;
  102. Split(u,L,R,edge[v],v);
  103. Split(R,s,z,edge[v],v+1);
  104. u = Merge(L,z);
  105. }
  106. void Insert(node *&u,node *v) {
  107. node *L,*R;
  108. Split(u,L,R,edge[v->id],v->id);
  109. L = Merge(L,v);
  110. u = Merge(L,R);
  111. }
  112. int Query(node *u,Point k) {
  113. if(!u) return -11;
  114. ll dir = (edge[u->id].t - edge[u->id].s) * (k - edge[u->id].s);
  115. if(dir > 0) {
  116. int res = Query(u->lc,k);
  117. if(res == -11) res = edge[u->id].id;
  118. return res;
  119. }
  120. else if(dir == 0) return max(edge[u->id].id,edge[u->id].other);
  121. else return Query(u->rc,k);
  122. }
  123. int n,k,Q,m,tot;
  124. ll pos[N];
  125. vector<int> del[N],ins[N];
  126. void preprocess() {
  127. sort(pos + 1,pos + tot + 1);
  128. tot = unique(pos + 1,pos + tot + 1) - pos - 1;
  129. for(int i = 1 ; i <= m ; ++i) {
  130. int tl = lower_bound(pos + 1 , pos + tot + 1 , edge[i].s.x ) - pos;
  131. int tr = lower_bound(pos + 1 , pos + tot + 1 , edge[i].t.x ) - pos;
  132. del[tr].push_back(i);
  133. ins[tl].push_back(i);
  134. }
  135. for(int i = 1 ; i <= m ; ++i) {
  136. nd[i] = tail++;
  137. nd[i]->id = i;
  138. nd[i]->pri = Rand();
  139. nd[i]->lc = nd[i]->rc = NULL;
  140. }
  141. for(int i = 1 ; i <= tot ; ++i) {
  142. rt[i] = rt[i - 1];
  143. int s1 = del[i].size(),s2 = ins[i].size();
  144. for(int j = 0 ; j < s1 ; ++j) Delete(rt[i],del[i][j]);
  145. for(int j = 0 ; j < s2 ; ++j) Insert(rt[i],nd[ins[i][j]]);
  146. }
  147. }
  148. int main() {
  149. #ifdef ivorysi
  150. freopen("f1.in","r",stdin);
  151. #endif
  152. scanf("%d",&n);
  153. int cnt = 0;
  154. while(n--) {
  155. ++cnt;
  156. scanf("%d",&k);
  157. for(int i = 1 ; i <= k ; ++i) {
  158. scanf("%lld%lld",&p[i].x,&p[i].y);
  159. }
  160. p[0] = p[k];
  161. ll Area = 0;
  162. for(int i = 1 ; i <= k ; ++i) {
  163. Area += p[i - 1] * p[i];
  164. }
  165. if(Area < 0) {
  166. reverse(p + 1 , p + k + 1);
  167. p[0] = p[k];
  168. }
  169. for(int i = 1 ; i <= k ; ++i) {
  170. pos[++tot] = p[i].x;
  171. if(p[i - 1].x < p[i].x) {
  172. edge[++m] = Seg(p[i - 1],p[i],cnt,-1);
  173. }
  174. else if(p[i - 1].x > p[i].x) {
  175. edge[++m] = Seg(p[i],p[i - 1],-1,cnt);
  176. }
  177. }
  178. }
  179. preprocess();
  180. scanf("%d",&Q);
  181. ll x,y;
  182. Point z;
  183. while(Q--) {
  184. scanf("%lld%lld",&x,&y);
  185. z = Point(x,y);
  186. if(x < pos[1] || x > pos[tot]) {
  187. puts("-1");
  188. fflush(stdout);
  189. continue;
  190. }
  191. int posx = lower_bound(pos + 1 ,pos + tot + 1 ,x) - pos;
  192. int ans = -1;
  193. ans = max(ans,Query(rt[posx - 1],z));
  194. if(x == pos[posx]) ans = max(ans,Query(rt[posx],z));
  195. printf("%d\n",ans);
  196. fflush(stdout);
  197. }
  198. return 0;
  199. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注