【BZOJ3600】没有人的算术 - 替罪羊树+线段树

题意:

 

题解:

Orz vfleaking……真·神题

做法大概是先把题意中定义的“数”都赋一个实数权值,用平衡树来维护整个从大到小排序过的序列,再用线段树查询最值;

这样做为什么是对的?考虑插入一个数$x$,我们已经知道了$x_L$和$x_R$在序列中的位置,就可以直接每次$O(1)$比较权值大小来找到$x$应该插入的位置,这样子单次插入是$O(logn)$的;

再考虑赋值,可以把根节点的区间设为$(0,1)$,然后每个点的权值都赋为这个区间中点的值,向子树递归赋值即可;由于平衡树树高是$O(logn)$的,最小精度限制就是$2^{-logn}=\frac{1}{n}$的,可以直接用double存;但是一个问题是普通的平衡树在旋转之后整棵子树的权值都需要重新计算,因此就要用不需要旋转的重量平衡树,这里我用的替罪羊树;

ps:貌似我写的替罪羊是假的……rebuild的地方会重复rec很多次……alpha小了会T,大了会WA……经过面对oj调参+玄学读优才卡时限过……

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7 #define inf 1000000007
  8 #define eps 1e-9
  9 using namespace std;
 10 typedef long long ll;
 11 typedef double db;
 12 const db alpha=0.865;
 13 int n,m,l,r,k,rt=0,cur,cnt=0,top=0,nw[500001],st[500001];
 14 db s[500001];
 15 char op[3];
 16 struct num{
 17     int x,y;
 18     num(){}
 19     num(int _x,int _y){
 20         x=_x,y=_y;
 21     }
 22     friend bool operator ==(num a,num b){
 23         return a.x==b.x&&a.y==b.y;
 24     }
 25     friend bool operator <(num a,num b){
 26         return a.x==b.x?s[a.y]<s[b.y]:s[a.x]<s[b.x];
 27     }
 28 };
 29 struct node{
 30     int ls,rs,siz;
 31     //db s;
 32     num v;
 33 }t[500001];
 34 struct _node{
 35     int v,p;
 36 }tr[500001];
 37 char buffer[6000010],*hd,*tl;
 38 inline char Getchar(){
 39     if(hd==tl){
 40         int len=fread(buffer,1,6000009,stdin);
 41         hd=buffer,tl=hd+len;
 42         if(hd==tl)
 43             return EOF;
 44     }
 45     return *hd++;
 46 }
 47 inline int rd(){
 48     register int x=0,f=1;
 49     char c;
 50     do{
 51         c=Getchar();
 52         if(c=='-')f=-1;
 53     }while(!isdigit(c));
 54     do{
 55         x=(x<<1)+(x<<3)+(c^48);
 56         c=Getchar();
 57     }while(isdigit(c));
 58     return x*f;
 59 }
 60 void getmx(num &a,num b){
 61     if((a.y==b.y&&a.x>b.x)||s[a.y]<s[b.y])a=b;
 62 }
 63 bool ndrb(int u){
 64     return t[t[u].ls].siz>t[u].siz*alpha+5||t[t[u].rs].siz>t[u].siz*alpha+5;
 65 }
 66 void rec(int u){
 67     if(t[u].ls)rec(t[u].ls);
 68     st[++top]=u;
 69     if(t[u].rs)rec(t[u].rs);
 70 }
 71 void rebuild(int &u,int l,int r,db L,db R){
 72     int mid=(l+r)/2;
 73     db Mid=(L+R)/2;
 74     u=st[mid];
 75     s[u]=Mid;
 76     t[u].ls=t[u].rs=0;
 77     if(l<mid)rebuild(t[u].ls,l,mid-1,L,Mid);
 78     if(mid<r)rebuild(t[u].rs,mid+1,r,Mid,R);
 79     t[u].siz=t[t[u].ls].siz+t[t[u].rs].siz;
 80 }
 81 void rb(int &u,db L,db R){
 82     top=0;
 83     rec(u);
 84     rebuild(u,1,top,L,R);
 85 }
 86 int ins(int &u,db L,db R,num x){
 87     db Mid=(L+R)/2;
 88     if(!u){
 89         u=++cnt;
 90         t[u].v=x;
 91         s[u]=Mid;
 92         t[u].ls=t[u].rs=0;
 93         t[u].siz=1;
 94         return u;
 95     }
 96     t[u].siz++;
 97     if(ndrb(u))rb(u,L,R);
 98     if(x==t[u].v)return u;
 99     else if(x<t[u].v)return ins(t[u].ls,L,Mid,x);
100     else return ins(t[u].rs,Mid,R,x);
101 }
102 void pushup(int u){
103     if(tr[u*2].v==tr[u*2+1].v||s[tr[u*2].v]>s[tr[u*2+1].v]){
104         tr[u].v=tr[u*2].v;
105         tr[u].p=tr[u*2].p;
106     }else{
107         tr[u].v=tr[u*2+1].v;
108         tr[u].p=tr[u*2+1].p;
109     }
110 }
111 void build(int l,int r,int u){
112     tr[u].v=1;
113     tr[u].p=l;
114     if(l==r)return;
115     int mid=(l+r)/2;
116     build(l,mid,u*2);
117     build(mid+1,r,u*2+1);
118 }
119 void updata(int l,int r,int u,int p){
120     if(l==r){
121         tr[u].v=nw[l];
122         tr[u].p=l;
123         return;
124     }
125     int mid=(l+r)/2;
126     if(p<=mid)updata(l,mid,u*2,p);
127     else updata(mid+1,r,u*2+1,p);
128     pushup(u);
129 }
130 num query(int l,int r,int u,int L,int R){
131     if(L<=l&&r<=R){
132         return num(tr[u].p,tr[u].v); 
133     }
134     int mid=(l+r)/2;
135     num ret(0,0);
136     if(L<=mid)getmx(ret,query(l,mid,u*2,L,R));
137     if(mid<R)getmx(ret,query(mid+1,r,u*2+1,L,R));
138     return ret;
139 } 
140 int main(){
141     #ifndef ONLINE_JUDGE
142     freopen("10.in","r",stdin);
143     freopen("my.out","w",stdout);
144     #endif 
145     //scanf("%d%d",&n,&m);
146     n=rd(),m=rd();
147     cur=ins(rt,0,1,num(1,0));
148     for(int i=1;i<=n;i++)nw[i]=cur;
149     build(1,n,1);
150     for(int i=1;i<=m;i++){
151         //scanf("%s%d%d",op,&l,&r);
152         char ch;
153         ch=Getchar();
154         while(ch!='C'&&ch!='Q')ch=Getchar();
155         l=rd(),r=rd();
156         if(ch=='C'){
157             //scanf("%d",&k);
158             k=rd();
159             nw[k]=ins(rt,0,1,num(nw[l],nw[r]));
160             updata(1,n,1,k);
161         }else printf("%d\n",query(1,n,1,l,r).x);
162     }
163     return 0;
164 }
posted @ 2019-01-10 21:32  DCDCBigBig  阅读(262)  评论(0编辑  收藏  举报