1. 程式人生 > >洛谷 P3380 【模板】二逼平衡樹(樹套樹)

洛谷 P3380 【模板】二逼平衡樹(樹套樹)

span r+ namespace chan 優先級 efi 當前 name cst

洛谷 P3380 【模板】二逼平衡樹(樹套樹)

線段樹套treap:

就是線段樹每個節點放一個treap。建樹復雜度應該是$n log n$,操作1,3,4,5的復雜度是$(log n)^2$,操作2的復雜度是$(log n)^3$。

操作3:找到線段樹的對應葉子節點後找到要刪除的值,在回溯的時候更新線段樹相關的每一個節點(在treap中去掉要刪除的值,再加入要加入的值)

操作1:將操作轉化為統計(這個區間[l,r]內小於x的數的個數)+1。那麽通過線段樹將區間分解,然後對分解出的每一個區間對應的treap求小於x的數的個數,最後將這些答案加起來再加一得到最終答案。

操作4:通過線段樹將區間分解,然後對分解出的每一個區間對應的treap求x的前驅,取這些前驅的最

值。

操作5:通過線段樹將區間分解,然後對分解出的每一個區間對應的treap求x的後繼,取這些後繼的最值。

操作2:咋一看似乎沒什麽好方法。看題解,可以將操作轉化為找出這個區間[l,r]內最小的x,使得區間內小於x的數不少於k-1個(即x的排名不低於k)二分答案即可。

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 #define MAXI 2147483647
  5 #define lc (num<<1)
  6 #define rc (num<<1|1)
  7
#define mid ((l+r)>>1) 8 int rand1() 9 { 10 static int x=471; 11 return x=(48271LL*x+1)%2147483647; 12 } 13 struct Node 14 { 15 Node* ch[2]; 16 int r;//優先級 17 int v;//value 18 int size;//維護子樹的節點個數 19 int num;//當前數字出現次數 20 int cmp(int x) const//要在當前節點的哪個子樹去查找,0左1右
21 { 22 if(x==v) return -1; 23 return v<x; 24 } 25 void upd() 26 { 27 size=num; 28 if(ch[0]!=NULL) size+=ch[0]->size; 29 if(ch[1]!=NULL) size+=ch[1]->size; 30 } 31 }nodes[3001000]; 32 int mem; 33 void rotate(Node* &o,int d) 34 { 35 Node* t=o->ch[d^1];o->ch[d^1]=t->ch[d];t->ch[d]=o; 36 o->upd();t->upd(); 37 o=t; 38 } 39 Node* getnode(){ return &nodes[mem++];} 40 void insert(Node* &o,int x) 41 { 42 if(o==NULL) 43 { 44 o=getnode();o->ch[0]=o->ch[1]=NULL; 45 o->v=x;o->r=rand1();o->num=1; 46 } 47 else 48 { 49 if(o->v==x) ++(o->num); 50 else 51 { 52 int d=o->v < x; 53 insert(o->ch[d],x); 54 if(o->r < o->ch[d]->r) rotate(o,d^1); 55 } 56 } 57 o->upd(); 58 } 59 void remove(Node* &o,int x) 60 { 61 int d=o->cmp(x); 62 if(d==-1) 63 { 64 if(o->num > 0) 65 { 66 --(o->num); 67 } 68 if(o->num == 0) 69 { 70 if(o->ch[0]==NULL) o=o->ch[1]; 71 else if(o->ch[1]==NULL) o=o->ch[0]; 72 else 73 { 74 int d2=o->ch[1]->r < o->ch[0]->r; 75 rotate(o,d2); 76 remove(o->ch[d2],x); 77 } 78 } 79 } 80 else remove(o->ch[d],x); 81 if(o!=NULL) o->upd(); 82 } 83 bool find(Node* o,int x) 84 { 85 int d; 86 while(o!=NULL) 87 { 88 d=o->cmp(x); 89 if(d==-1) return 1; 90 else o=o->ch[d]; 91 } 92 return 0; 93 } 94 int kth(Node* o,int k) 95 { 96 if(o==NULL||k<=0||k > o->size) return 0; 97 int s= o->ch[0]==NULL ? 0 : o->ch[0]->size; 98 if(k>s&&k<=s+ o->num) return o->v; 99 else if(k<=s) return kth(o->ch[0],k); 100 else return kth(o->ch[1],k-s- o->num); 101 } 102 int rk(Node* o,int x) 103 { 104 if(o==NULL) return 0; 105 int r=o->ch[0]==NULL ? 0 : o->ch[0]->size; 106 if(x==o->v) return r; 107 else if(x<o->v) return rk(o->ch[0],x); 108 else return r+ o->num +rk(o->ch[1],x); 109 } 110 int pre(Node* o,int x) 111 { 112 if(o==NULL) return -MAXI; 113 int d=o->cmp(x); 114 if(d<=0) return pre(o->ch[0],x); 115 else return max(o->v,pre(o->ch[1],x)); 116 } 117 int nxt(Node* o,int x) 118 { 119 if(o==NULL) return MAXI; 120 int d=o->cmp(x); 121 if(d!=0) return nxt(o->ch[1],x); 122 else return min(o->v,nxt(o->ch[0],x)); 123 } 124 Node* root[200100]; 125 int x,L,R,k,d,n,m;//所有操作的操作區間用[L,R]表示而不是[l,r] 126 int a[50010]; 127 128 129 int rk1(int l,int r,int num)//返回區間內小於x的數的個數 130 { 131 if(L<=l&&r<=R) 132 { 133 return rk(root[num],x); 134 } 135 int ans=0; 136 if(L<=mid) ans+=rk1(l,mid,lc); 137 if(mid<R) ans+=rk1(mid+1,r,rc); 138 return ans; 139 } 140 int pre1(int l,int r,int num) 141 { 142 if(L<=l&&r<=R) 143 { 144 return pre(root[num],x); 145 } 146 int ans=-2147483647; 147 if(L<=mid) ans=max(ans,pre1(l,mid,lc)); 148 if(mid<R) ans=max(ans,pre1(mid+1,r,rc)); 149 return ans; 150 } 151 int nxt1(int l,int r,int num) 152 { 153 if(L<=l&&r<=R) 154 { 155 return nxt(root[num],x); 156 } 157 int ans=2147483647; 158 if(L<=mid) ans=min(ans,nxt1(l,mid,lc)); 159 if(mid<R) ans=min(ans,nxt1(mid+1,r,rc)); 160 return ans; 161 } 162 void change(int l,int r,int num) 163 { 164 if(l<r) 165 { 166 if(k<=mid) change(l,mid,lc); 167 else change(mid+1,r,rc); 168 } 169 else 170 { 171 d=kth(root[num],1); 172 } 173 remove(root[num],d); 174 insert(root[num],x); 175 } 176 void build(int l,int r,int num) 177 { 178 for(int i=l;i<=r;i++) insert(root[num],a[i]); 179 if(l<r) 180 { 181 build(l,mid,lc); 182 build(mid+1,r,rc); 183 } 184 } 185 int main() 186 { 187 int i,idx,l,r; 188 scanf("%d%d",&n,&m); 189 for(i=1;i<=n;i++) scanf("%d",&a[i]); 190 build(1,n,1); 191 for(i=1;i<=m;i++) 192 { 193 scanf("%d",&idx); 194 if(idx==1) 195 { 196 scanf("%d%d%d",&L,&R,&x); 197 printf("%d\n",rk1(1,n,1)+1); 198 } 199 else if(idx==2) 200 { 201 scanf("%d%d%d",&L,&R,&k); 202 l=-1;r=100000000; 203 while(l<r-1) 204 { 205 x=(l+r)/2; 206 if(rk1(1,n,1)+1<=k) l=x; 207 else r=x; 208 } 209 x=r;printf("%d\n",pre1(1,n,1));; 210 } 211 else if(idx==3) 212 { 213 scanf("%d%d",&k,&x); 214 change(1,n,1); 215 } 216 else if(idx==4) 217 { 218 scanf("%d%d%d",&L,&R,&x); 219 printf("%d\n",pre1(1,n,1)); 220 } 221 else if(idx==5) 222 { 223 scanf("%d%d%d",&L,&R,&x); 224 printf("%d\n",nxt1(1,n,1)); 225 } 226 } 227 return 0; 228 }

洛谷 P3380 【模板】二逼平衡樹(樹套樹)