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可能为负数
哇,这个树套树真的是二逼,写完之后我整个人都二逼了啊QAQ。
做这道题前前后后起码花了20个小时,第一次脑补神奇平衡树爆零,第二次树状数组套动态开点线段树10分。一气之下直接上线段树+Splay居然过了。
这里有几点值得注意的:1、Splay的常数不能太大。2、后继查询的k可能有负数。3、线段树下面吊着的平衡树根是会变的,要时刻更新。4、唯一比较棘手的操作是区间K大,这里需要二分查找O(log^3 n)
下面是长出新高度的代码:
#include<cstdio>
#include<algorithm>
#define L 0
#define R 1
using namespace std;
const int maxn = 1e5 + 5;
int n, m, a;
inline void read(int & x) {
x = 0;
int f = 1;
char c = getchar();
while(c > '9' || c < '0') {
if(c == '-') f = -1; c = getchar();
}
while(c <= '9' && c >= '0') x = x * 10 + c - '0', c = getchar();
x *= f;
}
namespace Splay {
struct node {
int fa, ch[2], num, size, cnt;
}tree[maxn * 40];
int cnt;
void push_up(int rt) {
if(rt == 0) return;
int tl = tree[rt].ch[L];
int tr = tree[rt].ch[R];
tree[rt].size = tree[tl].size + tree[tr].size + tree[rt].cnt;
}
void rotate(int rt) {
int p = tree[rt].fa;
int a = tree[p].fa;
int l = tree[p].ch[R] == rt;
int r = l ^ 1;
if(a) tree[a].ch[tree[a].ch[R] == p] = rt;
tree[rt].fa = a, tree[p].fa = rt, tree[tree[rt].ch[r]].fa = tree[rt].ch[r] ? p : 0;
tree[p].ch[l] = tree[rt].ch[r], tree[rt].ch[r] = p;
push_up(p), push_up(rt), push_up(a);
}
inline void splay(int x, int y, int & root) {
int des = tree[y].fa;
while(tree[x].fa != des) {
int p = tree[x].fa;
int a = tree[p].fa;
if(p != y)
if((tree[a].ch[R] == p) ^ (tree[p].ch[R] == x)) rotate(x);
else rotate(p);
rotate(x);
}
if(y == root) root = x;
}
int find(int x, int root) {
int rt = root, last = 0, lm = 0;
while(tree[rt].num != x && rt != 0) {
if(tree[rt].num <= x && tree[rt].num > lm)
lm = tree[rt].num, last = rt;
rt = tree[rt].ch[x > tree[rt].num];
}
return rt == 0 ? last : rt;
}
int qrank(int x, int & root) {
int rt = find(x, root);
if(rt) splay(rt, root, root);
else return 0;
if(tree[rt].num == x) return tree[tree[rt].ch[L]].size;
else return tree[tree[rt].ch[L]].size + tree[rt].cnt;
}
int qnode(int rt, int & root, bool type) {
splay(rt, root, root);
rt = tree[rt].ch[type];
if(!rt) return -1;
while(tree[rt].ch[type ^ 1])
rt = tree[rt].ch[type ^ 1];
return rt;
}
void del(int x, int & root) {
int rt = find(x, root);
--tree[rt].cnt, --tree[rt].size;
if(tree[rt].cnt) {splay(rt, root, root);return;}
int pr = qnode(rt, root, 0);
int su = qnode(rt, root, 1);
if(pr == -1 && su == -1) {root = 0;return;}
else if(pr == -1) {splay(su, root, root), tree[su].ch[L] = 0, push_up(su);return;}
else if(su == -1) {splay(pr, root, root), tree[pr].ch[R] = 0, push_up(pr);return;}
else {splay(pr, root, root), splay(su, tree[pr].ch[R], root), tree[su].ch[L] = 0;}
push_up(su), push_up(pr);
}
void insert(int now, int x, int last, int & root) {
if(now == 0) {tree[++cnt] = (node){last, 0, 0, x, 1, 1};
tree[last].ch[tree[last].num < x] = cnt, splay(cnt, root, root); return;}
if(tree[now].num == x) {++tree[now].cnt, ++tree[now].size, splay(now, root, root);return;}
insert(tree[now].ch[tree[now].num < x], x, now, root);
}
}
namespace Segtree {
struct node {
int ch[2], l, r, Spn;
}tree[maxn << 1];
int cnt, root;
void build(int & rt, int l, int r) {
rt = ++cnt, tree[cnt].l = l, tree[cnt].r = r;
if(l == r) return;
int mid = l + r >> 1;
build(tree[rt].ch[L], l, mid);
build(tree[rt].ch[R], mid + 1, r);
}
//记得换根
void add(int rt, int pos, int x) {
int tl = tree[rt].l, tr = tree[rt].r;
if(tl == tr) {Splay::insert(tree[rt].Spn, x, 0, tree[rt].Spn);return;}
int mid = tl + tr >> 1;
if(pos <= mid) add(tree[rt].ch[L], pos, x);
else add(tree[rt].ch[R], pos, x);
Splay::insert(tree[rt].Spn, x, 0, tree[rt].Spn);
}
int del(int rt, int pos) {
int tl = tree[rt].l, tr = tree[rt].r;
if(tl == tr) {
int ans = Splay::tree[tree[rt].Spn].num;
Splay::del(Splay::tree[tree[rt].Spn].num, tree[rt].Spn);
return ans;
}
int mid = tl + tr >> 1, ans;
if(pos <= mid) ans = del(tree[rt].ch[L], pos);
else ans = del(tree[rt].ch[R], pos);
Splay::del(ans, tree[rt].Spn);
return ans;
}
void edit(int rt, int pos, int x) {
del(rt, pos);
add(rt, pos, x);
}
int qrank(int rt, int l, int r, int k) {
int tl = tree[rt].l, tr = tree[rt].r;
if(tl == l && tr == r) return Splay::qrank(k, tree[rt].Spn);
int mid = tl + tr >> 1;
if(r <= mid) return qrank(tree[rt].ch[L], l, r, k);
else if(l > mid) return qrank(tree[rt].ch[R], l, r, k);
else return qrank(tree[rt].ch[L], l, mid, k) + qrank(tree[rt].ch[R], mid + 1, r, k);
}
int qnum(int l, int r, int k) {
int al = 0, ar = 1e8 + 1;
while(al + 1 < ar) {
int mid = al + ar >> 1;
int ans = qrank(1, l, r, mid) + 1;
if(ans > k) ar = mid;
else al = mid;
}
return al;
}
int qnode(int rt, int l, int r, int k, bool type) {
int tl = tree[rt].l, tr = tree[rt].r;
if(tl == l && tr == r) {
Splay::insert(tree[rt].Spn, k, 0, tree[rt].Spn);
int ans = Splay::qnode(tree[rt].Spn, tree[rt].Spn, type);
Splay::del(k, tree[rt].Spn);
return ans == -1 ? -1 : Splay::tree[ans].num;
}
int mid = tl + tr >> 1;
if(r <= mid) return qnode(tree[rt].ch[L], l, r, k, type);
else if(l > mid) return qnode(tree[rt].ch[R], l, r, k, type);
else {
int ans1 = qnode(tree[rt].ch[L], l, mid, k, type);
int ans2 = qnode(tree[rt].ch[R], mid + 1, r, k, type);
if(type) {
if(ans1 == -1) return ans2 == -1 ? -1 : ans2;
if(ans2 == -1) return ans1;
else return min(ans2, ans1);
}else
return max(ans2, ans1);
}
}
}
int main() {
read(n), read(m);
Segtree::build(Segtree::root, 1, n);
for(register int i = 1; i <= n; ++i) read(a), Segtree::add(1, i, a);
int opt, a, b, c;
while(m--) {
read(opt);
if(opt != 3) read(a), read(b), read(c);
else read(a), read(b);
if(opt == 1) printf("%d\n", Segtree::qrank(1, a, b, c) + 1);
if(opt == 2) printf("%d\n", Segtree::qnum(a, b, c));
if(opt == 3) Segtree::edit(1, a, b);
if(opt == 4) {
int ans = Segtree::qnode(1, a, b, c, 0);
printf("%d\n", ans == -1 ? -2147483647 : ans);
}
if(opt == 5) {
int ans = Segtree::qnode(1, a, b, c, 1);
printf("%d\n", ans == -1 ? 2147483647 : ans);
}
}
return 0;
}
没有帐号? 立即注册