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

Sample Output

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

时间: 2024-12-19 09:24:29

BZOJ 3196 二逼平衡树的相关文章

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

BZOJ 3196 二逼平衡树 树套树

题目大意:...BZOJ挂了自己看去 好吧既然BZOJ挂了我还是贴上来吧0.0 破服务器 维护一种数据结构,提供下列操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 其实一开始觉得这题是划分树主席树之类的 然后去了解了一下发现完全写不了... 后来才知道原来是树套树 以前想过线段树套树状数组 这数据范围别说树套树了连树状数组都开不开 正解应该是

BZOJ 3196 二逼平衡树 线段树+treap

题意:链接 方法:线段树+treap的模板题 题解: 首先是对于整个树的定义,其实treap部分并没有什么区别,只不过是单root改变为多root而已. #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #define lson l,mid,rt<<1 #define rson mid+1,

BZOJ 3196 二逼平衡树 树套树(线段树套Treap)

题目大意: 写一种数据结构,他可以: 1.查询k在区间内的排名. 2.查询区间内排名为k的值 3.修改某一个值. 4.求k在区间内的前驱. 5.求k在区间内的后继. 思路:本来以为有什么只有神犇才知道的神一般的数据结构来维护它,问了别人之后,发现只是树套树.据说怎么套都行.我见识鄙陋,就只能线段树套Treap了. 这也是第一次写树套树,还1A了,有点开心. 写树套树,一定要确定自己对这两个树及其熟练,加上少量精细的思考,就可以完成树套树.(我只是弱渣,求神犇别D) 具体实现:第一层是线段树,第二

3196. 二逼平衡树【线段树套splay】

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在区间

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios

bzoj 3196 &amp;&amp; luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6372  Solved: 2406[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为