treap
Posted cyz666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了treap相关的知识,希望对你有一定的参考价值。
【平衡树要是手生了就糟了、】
Codefoces round 172 div1 E
虽然那题是可以n^2的,但是,主要是来敲treap的所以。。
1 #include <bits/stdc++.h> 2 #define DB double 3 using namespace std; 4 const DB eps=0.00000001; 5 int cnt,rt,x,n,t,fl; DB M,P,Q,X,w[7000],G[7000],Ans,A[1000][4]; 6 struct O{ 7 DB p,q,pp,k,b,kx,bx,x; 8 int l,r,f; 9 }a[30000]; 10 void ADD(int u,DB k,DB b){ 11 if (!u) return; 12 a[u].kx+=k; a[u].k+=k; 13 a[u].bx+=b; a[u].b+=b; 14 } 15 void up(int u){ 16 if (a[u].l) a[u].pp=a[a[u].l].pp; 17 else a[u].pp=a[u].p; 18 } 19 void down(int u){ 20 if (!u) return; 21 if (fabs(a[u].x)>eps){ 22 DB x=a[u].x; a[u].x=0; int v; 23 if (v=a[u].l){ 24 a[v].pp+=x; 25 a[v].p+=x; a[v].q+=x; 26 a[v].b-=x*a[v].k; 27 a[v].bx-=x*a[v].kx; 28 a[v].x+=x; 29 } 30 if (v=a[u].r){ 31 a[v].pp+=x; 32 a[v].p+=x; a[v].q+=x; 33 a[v].b-=x*a[v].k; 34 a[v].bx-=x*a[v].kx; 35 a[v].x+=x; 36 } 37 } 38 if (fabs(a[u].kx)>eps||fabs(a[u].bx)>eps){ 39 ADD(a[u].l,a[u].kx,a[u].bx); 40 ADD(a[u].r,a[u].kx,a[u].bx); 41 a[u].kx=a[u].bx=0; 42 } 43 } 44 void add(int u,DB t,DB x){ 45 if (!u) return; 46 if (a[u].pp+eps>t){ 47 a[u].pp+=x; 48 a[u].p+=x; a[u].q+=x; 49 a[u].b-=x*a[u].k; 50 a[u].bx-=x*a[u].kx; 51 a[u].x+=x; return; 52 } 53 down(u); 54 if (a[u].p+eps>t){ 55 a[u].p+=x; a[u].q+=x; 56 a[u].b-=x*a[u].k; 57 a[u].bx-=x*a[u].kx; 58 add(a[u].l,t,x); 59 } 60 add(a[u].r,t,x); 61 up(u); 62 } 63 void NEW(DB p,DB q,DB k,DB b){ 64 ++t; a[t].f=(1ll*rand()*rand()+rand())%1000000000; 65 a[t].p=a[t].pp=p; a[t].q=q; 66 a[t].k=k; a[t].b=b; 67 } 68 int find(int u){ 69 down(u); 70 if (a[u].q*a[u].k+a[u].b<-eps) 71 if (a[u].r) return find(a[u].r); else return fl=2,u; 72 if (a[u].p*a[u].k+a[u].b>eps) 73 if (a[u].l) return find(a[u].l); else return fl=1,u; 74 return u; 75 } 76 void RR(int &u){ 77 int v=a[u].l; down(v); a[u].l=a[v].r; 78 a[v].r=u; up(u); up(v); u=v; 79 } 80 void LL(int &u){ 81 int v=a[u].r; down(v); a[u].r=a[v].l; 82 a[v].l=u; up(u); up(v); u=v; 83 } 84 void del(int &u,int v){ 85 down(u); 86 if (u==v){ 87 if (!a[u].l||!a[u].r) 88 u=a[u].l+a[u].r; else 89 if (a[a[u].l].f<a[a[u].r].f) 90 RR(u),del(a[u].r,v); 91 else 92 LL(u),del(a[u].l,v); 93 }else 94 if (a[v].p<a[u].p) del(a[u].l,v); 95 else del(a[u].r,v); 96 up(u); 97 } 98 void join(int &u,int v){ 99 if (!u) {u=v; return;} 100 down(u); 101 if (a[v].p<a[u].p){ 102 join(a[u].l,v); up(u); 103 if (a[a[u].l].f<a[u].f) RR(u); 104 }else{ 105 join(a[u].r,v); up(u); 106 if (a[a[u].r].f<a[u].f) LL(u); 107 } 108 } 109 int main(){ 110 scanf("%d%lf%lf%lf",&n,&M,&P,&Q); 111 for (int i=1;i<=n;++i) scanf("%lf",&w[i]); 112 rt=1; NEW(1,M,2,-2*w[1]); 113 for (int i=2;i<=n;++i){ 114 fl=0; x=find(rt); 115 if (fl) X=fl==1?a[x].p:a[x].q; else X=-a[x].b/a[x].k; 116 del(rt,x); G[i-1]=X; 117 if (a[x].p<X-eps) NEW(a[x].p,X,a[x].k,a[x].b),join(rt,t); 118 if (X<a[x].q-eps) NEW(X,a[x].q,a[x].k,a[x].b),join(rt,t); 119 add(rt,X,Q-P); add(rt,1,P); 120 if (P<Q-eps) NEW(X+P,X+Q,0,0),join(rt,t); 121 ADD(rt,2,-2*w[i]); 122 } 123 fl=0; x=find(rt); 124 if (fl) X=fl==1?a[x].p:a[x].q; else X=-a[x].b/a[x].k; 125 G[n]=min(X,M); 126 for (int i=n-1;i;--i){ 127 if (G[i]+P>G[i+1]) G[i]=G[i+1]-P; 128 if (G[i]+Q<G[i+1]) G[i]=G[i+1]-Q; 129 } 130 for (int i=1;i<=n;++i) printf("%.6lf ",G[i]); 131 for (int i=1;i<=n;++i) Ans+=(G[i]-w[i])*(G[i]-w[i]); 132 printf("\n%.6lf\n",Ans); 133 return 0; 134 }
这里总结一下经验。
① 打标记(这里当然是针对标记下传的那种):
线段树也一样,如果要打多种互相影响的标记,不要忘了先后顺序。
就如线段树中最简单的,加和乘同时存在的标记一样。
首先是一定要搞清楚 一个节点上的标记,每个标记的先后顺序。 显然 先乘法,再加法比较好。
所以,在往一个节点附乘法标记时,要把加标记也乘上要乘的值,保持了每个节点上的标记顺序。
在下传标记时,也要以同样的顺序下传。
如果有些复杂的标记,想不懂如何合并(就是 加标记乘上要乘的值 那种操作),可以考虑把节点要维护的信息当成一维矩阵,比如[x,y,...,1]。
然后,标记就变成一个二维矩阵了。(维护的信息加一个1,是为了要加常数的标记)
② 这里把上面的标程模板化,留下一些常用操作(可能还是有漏洞,比如要套用有reverse的题的话还得再仔细看看)。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int rt,cnt; 4 struct O{ 5 int l,r,f; 6 }a[30000]; 7 void up(int u){ 8 //update 9 } 10 void down(int u){ 11 if (!u) return; 12 int l=a[u].l,r=a[u].r; 13 if (a[u].tag1){ 14 if (l){ 15 } 16 if (r){ 17 } 18 } 19 /* 20 push down the tags in order 21 */ 22 } 23 int NEW(){ 24 ++cnt; a[cnt].f=(1ll*rand()*rand()+rand())%1000000000; 25 /* 26 initial 27 */ 28 return cnt; 29 } 30 int find(int u){ 31 down(u); 32 33 return u; 34 } 35 void RR(int &u){ //left son up 36 int v=a[u].l; down(v); //don‘t forget down! 37 a[u].l=a[v].r; a[v].r=u; 38 up(u); up(v); u=v; 39 } 40 void LL(int &u){ 41 int v=a[u].r; down(v); 42 a[u].r=a[v].l; a[v].l=u; 43 up(u); up(v); u=v; 44 } 45 void del(int &u,int v){ 46 down(u); 47 if (u==v){ 48 if (!a[u].l||!a[u].r) 49 u=a[u].l+a[u].r; 50 else 51 if (a[a[u].l].f>a[a[u].r].f) 52 RR(u),del(a[u].r,v); 53 else 54 LL(u),del(a[u].l,v); 55 }else 56 if (/*in left*/) del(a[u].l,v); 57 else del(a[u].r,v); 58 up(u); 59 } 60 void join(int &u,int v){ 61 if (!u) {u=v; return;} 62 down(u); 63 if (/*in left*/){ 64 join(a[u].l,v); up(u); 65 if (a[a[u].l].f>a[u].f) RR(u); 66 }else{ 67 join(a[u].r,v); up(u); 68 if (a[a[u].r].f>a[u].f) LL(u); 69 } 70 } 71 int main(){ 72 73 return 0; 74 }
以上是关于treap的主要内容,如果未能解决你的问题,请参考以下文章