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 }
Steamm

这里总结一下经验。

① 打标记(这里当然是针对标记下传的那种):

  线段树也一样,如果要打多种互相影响的标记,不要忘了先后顺序。

  就如线段树中最简单的,加和乘同时存在的标记一样。

    首先是一定要搞清楚 一个节点上的标记,每个标记的先后顺序。  显然 先乘法,再加法比较好。

    所以,在往一个节点附乘法标记时,要把加标记也乘上要乘的值,保持了每个节点上的标记顺序。

    在下传标记时,也要以同样的顺序下传。

  如果有些复杂的标记,想不懂如何合并(就是 加标记乘上要乘的值 那种操作),可以考虑把节点要维护的信息当成一维矩阵,比如[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 }
noob

 

posted @ 2017-11-17 19:42  cyz666  阅读(382)  评论(0编辑  收藏  举报