BZOJ3196 二逼平衡树

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB

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可能为负数


所以说我可能真的不适合数据结构,泪流满面"^"

我没有吃饭加浪费了一个晚自习的结果居然是一处maxv写成了maxn,终于没有写错splay居然又开错了数组有木有有木有。。。

我这时的心情是悲愤的,然而并没有什么卵用,再立flag,明天数据结构绝对1A

线段树套Splay,对于二号询问直接二分答案,Splay还是记得开哨兵

有时候函数开多一点代码反而更好写


  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long LL;
  4 template <class _T> inline void read(_T &_x) {
  5     int _t; bool flag = false;
  6     while ((_t = getchar()) != ‘-‘ && (_t < ‘0‘ || _t > ‘9‘)) ;
  7     if (_t == ‘-‘) _t = getchar(), flag = true; _x = _t - ‘0‘;
  8     while ((_t = getchar()) >= ‘0‘ && _t <= ‘9‘) _x = _x * 10 + _t - ‘0‘;
  9     if (flag) _x = -_x;
 10 }
 11 const int maxn = 50010;
 12 const int inf = 2147483647;
 13 namespace S {
 14     const int maxv = 4e6 + 5;
 15     int *root;
 16     int v[maxv], f[maxv], ch[maxv][2], sz[maxv], cnt[maxv];
 17     int st[maxv], top, tot;
 18     inline int newnode(int val) {
 19         if (!top) st[top++] = ++tot;
 20         int cur = st[--top];
 21         v[cur] = val;
 22         f[cur] = ch[cur][0] = ch[cur][1] = 0;
 23         sz[cur] = cnt[cur] = 1;
 24         return cur;
 25     }
 26     inline void update(int rt) {
 27         sz[rt] = sz[ch[rt][0]] + sz[ch[rt][1]] + cnt[rt];
 28     }
 29     inline void init(int &rt) {
 30         rt = newnode(-inf);
 31         ch[rt][1] = newnode(inf);
 32         f[ch[rt][1]] = rt;
 33         update(rt);
 34     }
 35     inline void rotate(int c) {
 36         int b = f[c], a = f[b], x = ch[b][1]==c;
 37         ch[b][x] = ch[c][x ^ 1], f[ch[b][x]] = b;
 38         ch[c][x ^ 1] = b, f[b] = c;
 39         if (a) ch[a][ch[a][1]==b] = c; else *root = c;
 40         f[c] = a; update(b);
 41     }
 42     inline int splay(int c, int a = 0) {
 43         for (int b; (b = f[c]) != a; rotate(c)) if (f[b] != a)
 44             rotate((ch[f[b]][1]==b)==(ch[b][1]==c)?b:c);
 45         update(c); return c;
 46     }
 47     inline int query_pre(int rt, int val) {
 48         int ret = 0, ori = f[rt];
 49         do {
 50             if (v[rt] < val) ret = rt;
 51             rt = ch[rt][v[rt] < val];
 52         } while (rt);
 53         return splay(ret, ori);
 54     }
 55     inline int query_suc(int rt, int val) {
 56         int ret = 0, ori = f[rt];
 57         do {
 58             if (v[rt] > val) ret = rt;
 59             rt = ch[rt][v[rt] <= val];
 60         } while (rt);
 61         return splay(ret, ori);
 62     }
 63     inline int pre(int rt, int a = 0) {
 64         rt = ch[rt][0];
 65         while (ch[rt][1]) rt = ch[rt][1];
 66         return splay(rt, a);
 67     }
 68     inline int suc(int rt, int a = 0) {
 69         rt = ch[rt][1];
 70         while (ch[rt][0]) rt = ch[rt][0];
 71         return splay(rt, a);
 72     }
 73     inline void remove(int rt, int val) {
 74         int x = query_pre(rt, val);
 75         int y = suc(x, x);
 76         if (cnt[y] > 1) --cnt[y];
 77         else {
 78             int z = suc(y, x);
 79             st[top++] = y, ch[z][0] = 0, y = z;
 80         }
 81         update(y), update(x);
 82     }
 83     inline void insert(int &rt, int val) {
 84         root = &rt;
 85         int x = query_pre(rt, val);
 86         int y = suc(x, x);
 87         if (v[y] == val) ++cnt[y];
 88         else {
 89             int z = ch[y][0] = newnode(val);
 90             f[z] = y;
 91         }
 92         update(y), update(x);
 93     }
 94     inline void change(int &rt, int ori, int to) {
 95         root = &rt;
 96         remove(rt, ori);
 97         insert(rt, to);
 98     }
 99     inline int Query_cnt(int &rt, int val) {
100         root = &rt;
101         query_suc(rt, val);
102         return sz[ch[rt][0]] - 1;
103     }
104     inline int Query_suc(int &rt, int val) {
105         root = &rt;
106         return v[query_suc(rt, val)];
107     }
108     inline int Query_pre(int &rt, int val) {
109         root = &rt;
110         return v[query_pre(rt, val)];
111     }
112     inline int Query_rk(int &rt, int val) {
113         root = &rt;
114         int x = query_pre(rt, val);
115         return sz[ch[x][0]] + cnt[x] - 1;
116     }
117 }
118 int n, m, a[maxn], root[maxn * 20];
119 #define lson rt << 1, l, mid
120 #define rson rt << 1 | 1, mid + 1, r
121 void build(int rt, int l, int r) {
122     S::init(root[rt]);
123     for (int i = l; i <= r; ++i)
124         S::insert(root[rt], a[i]);
125     if (l == r) return ;
126     int mid = (l + r) >> 1;
127     build(lson), build(rson);
128 }
129 int query_cnt(int rt, int l, int r, int L, int R, int val) { //cnt of less or equal
130     if (L <= l && r <= R) return S::Query_cnt(root[rt], val);
131     int mid = (l + r) >> 1, ret = 0;
132     if (L <= mid) ret += query_cnt(lson, L, R, val);
133     if (mid < R) ret += query_cnt(rson, L, R, val);
134     return ret;
135 }
136 int query_pre(int rt, int l, int r, int L, int R, int val) { //less than val
137     if (L <= l && r <= R) return S::Query_pre(root[rt], val);
138     int mid = (l + r) >> 1, ret = -inf;
139     if (L <= mid) ret = max(ret, query_pre(lson, L, R, val));
140     if (mid < R) ret = max(ret, query_pre(rson, L, R, val));
141     return ret;
142 }
143 int query_suc(int rt, int l, int r, int L, int R, int val) { //more than val
144     if (L <= l && r <= R) return S::Query_suc(root[rt], val);
145     int mid = (l + r) >> 1, ret = inf;
146     if (L <= mid) ret = min(ret, query_suc(lson, L, R, val));
147     if (mid < R) ret = min(ret, query_suc(rson, L, R, val));
148     return ret;
149 }
150 int query_precnt(int rt, int l, int r, int L, int R, int val) {
151     if (L <= l && r <= R) return S::Query_rk(root[rt], val);
152     int mid = (l + r) >> 1, ret = 0;
153     if (L <= mid) ret += query_precnt(lson, L, R, val);
154     if (mid < R) ret += query_precnt(rson, L, R, val);
155     return ret;
156 }
157 void update(int rt, int l, int r, int pos, int val) { // update pos to val
158     S::change(root[rt], a[pos], val);
159     if (l == r) return ;
160     int mid = (l + r) >> 1;
161     if (pos <= mid) update(lson, pos, val);
162     else update(rson, pos, val);
163 }
164 inline int Query_kth(int L, int R, int k) {
165     int l = 0, r = 1e8, mid;
166     while (l < r) {
167         mid = (l + r) >> 1;
168         if (query_cnt(1, 1, n, L, R, mid) >= k) r = mid;
169         else l = mid + 1;
170     }
171     return l;
172 }
173 inline int Query_pre(int L, int R, int val) {
174     return query_pre(1, 1, n, L, R, val);
175 }
176 inline int Query_suc(int L, int R, int val) {
177     return query_suc(1, 1, n, L, R, val);
178 }
179 inline int Query_rk(int L, int R, int val) {
180     return query_precnt(1, 1, n, L, R, val) + 1;
181 }
182 inline void Update(int pos, int val) {
183     update(1, 1, n, pos, val);
184     a[pos] = val;
185 }
186 int main() {
187     //freopen("3196.in", "r", stdin);
188     //freopen("3196.out", "w", stdout);
189     read(n), read(m);
190     for (int i = 1; i <= n; ++i) read(a[i]);
191     build(1, 1, n);
192     for (int i = 1, op, x, y, z; i <= m; ++i) {
193         read(op);
194         switch (op) {
195             case 1:
196                 read(x), read(y), read(z);
197                 printf("%d\n", Query_rk(x, y, z));
198                 break;
199             case 2:
200                 read(x), read(y), read(z);
201                 printf("%d\n", Query_kth(x, y, z));
202                 break;
203             case 3:
204                 read(x), read(y);
205                 Update(x, y);
206                 break;
207             case 4:
208                 read(x), read(y), read(z);
209                 printf("%d\n", Query_pre(x, y, z));
210                 break;
211             case 5:
212                 read(x), read(y), read(z);
213                 printf("%d\n", Query_suc(x, y, z));
214                 break;
215         }
216     }
217     return 0;
218 }

时间: 2024-11-02 06:09:27

BZOJ3196 二逼平衡树的相关文章

BZOJ3196二逼平衡树【树套树】

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

BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线段树套vector水过啦!!! 每个ZKW线段树的节点保存一个vector 操作1在分出的vector上查询比它小的数有多少个然后相加再加1 操作2二分再上操作1 操作3修改需要修改的节点的vector 操作4在分出vector上查询前驱取最大 操作5与操作4同理 luogu主站5772ms上卡过,

bzoj3196 二逼平衡树 线段树套平衡树

题意:您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 题解:树套树,外层是一棵线段树,每个节点下有一棵平衡树(平衡树记录ls,rs,因此记录根节点就可以遍历整棵树),先不考虑空间问题,ask(l,r)可以分成多个线段树区间,每个区间下有平衡树可以查询排名,1&3-5操

BZOJ3196 二逼平衡树 【线段树套平衡树】

题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 输入格式 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名 若

洛谷3380 二逼平衡树(树套树)

题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647) 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647) 注意上面两条要求和tyvj或者bzoj不一样,请注意 输入输出格式 输入格式: 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,

二逼平衡树

题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647) 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647) 注意上面两条要求和tyvj或者bzoj不一样,请注意 输入输出格式 输入格式: 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,

bzoj3196Tyvj 1730 二逼平衡树

bzoj3196Tyvj1730二逼平衡树 题意: 维护一个数列,操作:查询k在区间内的排名.查询区间内排名为k的值3.修改某一位上的数值.查询k在区间内的前驱(前驱定义为小于x,且最大的数).查询k在区间内的后继(后继定义为大于x,且最小的数) 题解: 线段树套treap,我写了一个星期QAQ第一.三个操作直接搞:第二个操作就二分那个值,然后查它在区间内的排名:第四.五个操作就当查询值≤(≥)当前节点就往左(右)走,用一个全局变量记往左(右)走时遍历过的最大(小)值.反思:本弱各种写挂,以前从

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] 二逼平衡树 树状数组套主席树

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在区间内的后继(后继定义为