BZOJ 3196 二逼平衡树
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
Output
对于操作1,2,4,5各输出一行,表示查询结果
Sample Input
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
Sample Output
2
4
3
4
9
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
写了不很久,但是交上去一直都是TLE,发现splay被卡了。最后采用随机提根法,卡过去了。
一道树套树的裸题(很明显线段树套平衡树)。
1 #include<iostream> 2 #include<queue> 3 #include<cstdio> 4 #include<cstdlib> 5 using namespace std; 6 7 #define inf (1<<29) 8 #define lim (100000000) 9 #define maxn (50010) 10 #define maxm (3000010) 11 int n,m,root[maxn*4],seq[maxn]; 12 struct SPLAY 13 { 14 queue <int> team; int cnt,ch[maxm][2],fa[maxm],key[maxm],t[maxm],size[maxm]; 15 16 inline int newnode() 17 { 18 int ret; 19 if (!team.empty()) ret = team.front(),team.pop(); 20 else ret = ++cnt; 21 fa[ret] = ch[ret][0] = ch[ret][1] = t[ret] = 0; 22 return ret; 23 } 24 25 inline void updata(int now) { size[now] = size[ch[now][0]] + size[ch[now][1]] + t[now]; } 26 27 inline void rotate(int x) 28 { 29 int y = fa[x],z = fa[y],l = ch[y][1] == x,r = l^1; 30 if (z) ch[z][ch[z][1] == y] = x; fa[x] = z; 31 if (ch[x][r]) fa[ch[x][r]] = y; ch[y][l] = ch[x][r]; 32 ch[x][r] = y; fa[y] = x; 33 updata(y); updata(x); 34 } 35 36 inline void splay(int x,int rt) 37 { 38 while (fa[x]) 39 { 40 int y = fa[x],z = fa[y]; 41 if (z) 42 { 43 if ((ch[y][0] == x)^(ch[z][0] == y)) rotate(x); 44 else rotate(y); 45 } 46 rotate(x); 47 } 48 root[rt] = x; 49 } 50 51 inline void init(int rt) 52 { 53 int p = newnode(),q = newnode(); 54 root[rt] = p; ch[p][1] = q; fa[q] = p; 55 t[p]++; key[p] = -inf; t[q]++; key[q] = inf; 56 updata(q); updata(p); 57 } 58 59 inline int find(int w,int rt,int sign) 60 { 61 int now = root[rt],ret; 62 while (now) 63 { 64 if (!sign) 65 { 66 if (key[now] == w) return now; 67 now = ch[now][key[now]<w]; 68 } 69 else if (sign == 1) 70 { 71 if (key[now] < w) ret = now,now = ch[now][1]; 72 else now = ch[now][0]; 73 } 74 else if (sign == 2) 75 { 76 if (key[now] > w) ret = now,now = ch[now][0]; 77 else now = ch[now][1]; 78 } 79 else 80 { 81 if (key[now] >= w) ret = now,now = ch[now][0]; 82 else now = ch[now][1]; 83 } 84 } 85 return ret; 86 } 87 88 inline void erase(int w,int rt) 89 { 90 int p = find(w,rt,0); 91 while (ch[p][0]||ch[p][1]) 92 { 93 if (ch[p][0]) 94 { 95 if (root[rt] == p) root[rt] = ch[p][0]; 96 rotate(ch[p][0]); 97 } 98 else 99 { 100 if (root[rt] == p) root[rt] = ch[p][1]; 101 rotate(ch[p][1]); 102 } 103 } 104 int now = p; 105 if (!--t[now]) ch[fa[now]][key[fa[now]] < key[now]] = 0,team.push(now); 106 else updata(now); 107 while (now = fa[now],now) updata(now); 108 } 109 110 inline void insert(int w,int rt) 111 { 112 int now = root[rt],pre = 0; 113 while (now) 114 { 115 if (key[now] == w) { ++t[now]; break; } 116 pre = now; now = ch[now][w > key[now]]; 117 } 118 if (!now) 119 now = newnode(),fa[now] = pre,ch[pre][w > key[pre]] = now,key[now] = w,++t[now]; 120 for (pre = now;pre;pre = fa[pre]) updata(pre); 121 if (w & 1) splay(now,rt); 122 } 123 124 inline int rank(int w,int rt) 125 { 126 int p = find(w,rt,3); splay(p,rt); 127 return size[ch[p][0]]; 128 } 129 }tree; 130 131 inline void build(int l,int r,int now) 132 { 133 tree.init(now); 134 for (int i = l;i <= r;++i) tree.insert(seq[i],now); 135 if (l == r) return; 136 int mid = (l + r) >> 1; 137 build(l,mid,now<<1); build(mid+1,r,now<<1|1); 138 } 139 140 inline int rank(int l,int r,int ql,int qr,int now,int w) 141 { 142 if (ql <= l && qr >= r) return tree.rank(w,now)-1; 143 int mid = (l + r) >> 1; 144 if (qr <= mid) return rank(l,mid,ql,qr,now<<1,w); 145 else if (ql > mid) return rank(mid+1,r,ql,qr,now<<1|1,w); 146 else return rank(l,mid,ql,mid,now<<1,w)+rank(mid+1,r,ql,qr,now<<1|1,w); 147 } 148 149 inline void change(int l,int r,int now,int pos,int w) 150 { 151 tree.erase(seq[pos],now); tree.insert(w,now); 152 if (l == r) return; 153 int mid = (l + r) >> 1; 154 if (pos <= mid) change(l,mid,now<<1,pos,w); 155 else change(mid+1,r,now<<1|1,pos,w); 156 } 157 158 inline int ask(int l,int r,int ql,int qr,int now,int w,int sign) 159 { 160 if (ql <= l && qr >= r) return tree.key[tree.find(w,now,sign)]; 161 int mid = (l + r)>>1; 162 if (qr <= mid) return ask(l,mid,ql,qr,now<<1,w,sign); 163 else if (ql > mid) return ask(mid+1,r,ql,qr,now<<1|1,w,sign); 164 else 165 { 166 if (sign == 1) return max(ask(l,mid,ql,mid,now<<1,w,sign),ask(mid+1,r,mid+1,qr,now<<1|1,w,sign)); 167 else return min(ask(l,mid,ql,mid,now<<1,w,sign),ask(mid+1,r,mid+1,qr,now<<1|1,w,sign)); 168 } 169 } 170 171 int main() 172 { 173 freopen("3196.in","r",stdin); 174 freopen("3196.out","w",stdout); 175 scanf("%d %d",&n,&m); 176 for (int i = 1;i <= n;++i) scanf("%d",seq+i); 177 build(1,n,1); 178 while (m--) 179 { 180 int opt; scanf("%d",&opt); 181 if (opt == 1) 182 { 183 int l,r,w; scanf("%d %d %d",&l,&r,&w); 184 printf("%d\n",rank(1,n,l,r,1,w)+1); 185 } 186 else if (opt == 2) 187 { 188 int l,r,k; scanf("%d %d %d",&l,&r,&k); 189 int ll = 0,rr = lim; 190 while (ll <= rr) 191 { 192 int mid = (ll + rr) >> 1; 193 if (rank(1,n,l,r,1,mid)+1>k) rr = mid - 1; 194 else ll = mid + 1; 195 } 196 printf("%d\n",rr); 197 } 198 else if (opt == 3) 199 { 200 int pos,w; scanf("%d %d",&pos,&w); 201 change(1,n,1,pos,w); seq[pos] = w; 202 } 203 else 204 { 205 int l,r,w; scanf("%d %d %d",&l,&r,&w); 206 printf("%d\n",ask(1,n,l,r,1,w,opt-3)); 207 } 208 } 209 fclose(stdin); fclose(stdout); 210 return 0; 211 }
高考结束,重新回归。