1. 程式人生 > >【BZOJ3600】沒有人的算術 - 替罪羊樹+線段樹

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