1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 867 Solved: 350
[ Submit][ Status][ Discuss]
Description
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。 你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。 第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。 接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
Input
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Output
Sample Input
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
6
HINT
20%的数据中,m,n≤100;
40%的数据中,m,n≤1000;
100%的数据中,m,n≤10000。
疼,上手第一个题解就树套树
思路:
由于是维护区间,于是很容易想到用线段树
但是线段树不具备动态维护区间第k大值的能力(线段树可以动态修改,但查询效率。。。)
于是就不难想到用平衡树充当并维护线段树中的线段,这样可以做到对于一个给定的值,查询在这个线段中有多少个比它小的值
有了这个功能,我们就可以二分答案,放入树套树中查询
源代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
const int Maxn = 10010;
class Splay_Node
{
public:
int data, size;
Splay_Node *lch, *rch, *fa;
Splay_Node()
{
data = -100000000;
size = 0;
lch = rch = NULL;
}
~Splay_Node(){}
};
void update(Splay_Node *x)
{
x -> size = 1;
if(x -> lch != NULL) x -> size += x -> lch -> size;
if(x -> rch != NULL) x -> size += x -> rch -> size;
}
void Zig(Splay_Node *x)
{
Splay_Node *f, *g;
f = x -> fa, g = f -> fa;
if(g && f == g -> lch) g -> lch = x;
else if(g && f == g -> rch) g -> rch = x;
x -> fa = g;
f -> lch = x -> rch;
if(x -> rch) x -> rch -> fa = f;
x -> rch = f;
f -> fa = x;
update(f);
update(x);
}
void Zag(Splay_Node *x)
{
Splay_Node *f, *g;
f = x -> fa, g = f -> fa;
if(g && f == g -> lch) g -> lch = x;
else if(g && f == g -> rch) g -> rch = x;
x -> fa = g;
f -> rch = x -> lch;
if(x -> lch) x -> lch -> fa = f;
x -> lch = f;
f -> fa = x;
update(f);
update(x);
}
class Splay
{
public:
Splay_Node *t;
Splay_Node *root;
Splay_Node **recycle_bin;
~Splay(){}
int tot, top;
Splay()
{
root = NULL;
tot = 0;
top = -1;
}
void resize(const int &size)
{
t = new Splay_Node [size];
recycle_bin = new Splay_Node* [size];
}
void splay(Splay_Node* x)
{
Splay_Node *f, *g;
root = x;
while(x -> fa)
{
f = x -> fa, g = f -> fa;
if(g == NULL)
{
f -> rch == x ? Zag(x) : Zig(x);
}
else
{
if(g -> lch == f)
{
if(f -> lch == x)
{
Zig(f);
Zig(x);
}
else
{
Zag(x);
Zig(x);
}
}
else
{
if(f -> rch == x)
{
Zag(f);
Zag(x);
}
else
{
Zig(x);
Zag(x);
}
}
}
}
}
Splay_Node* alloc()
{
if(top == -1)
{
return &t[tot++];
}
else
{
return recycle_bin[top--];
}
}
void insert(int x, Splay_Node* &cur, Splay_Node *fa)
{
if(cur == NULL)
{
cur = alloc();
cur -> data = x;
cur -> lch = cur -> rch = NULL;
cur -> size = 1;
cur -> fa = fa;
}
else
{
insert(x, x < cur -> data ? cur -> lch : cur -> rch, cur);
update(cur);
}
}
void build(int *arr, int size)
{
for(int i = 0; i < size; ++i)
insert(arr[i], root, NULL);
}
int Query(int x, Splay_Node *cur)
{
if(cur == NULL) return 0;
if(cur -> data >= x)
{
return Query(x, cur -> lch);
}
else
{
if(cur -> lch)
{
return cur -> lch ->size + 1 + Query(x, cur -> rch);
}
else
{
return 1 + Query(x, cur -> rch);
}
}
}
void del(int val, Splay_Node *cur)
{
while(cur -> data != val)
{
if(cur -> data > val) cur = cur -> lch;
else cur = cur -> rch;
}
splay(cur);
root = cur -> lch;
if(cur -> lch) cur -> lch -> fa = NULL;
if(cur -> rch) cur -> rch -> fa = NULL;
Splay_Node *tmp = cur -> lch;
if(tmp == NULL)
{
root = cur -> rch;
if(cur->rch) cur -> rch -> fa = NULL;
}
else
{
while(tmp -> rch)
{
tmp = tmp -> rch;
}
splay(tmp);
root -> rch = cur -> rch;
if(cur -> rch) cur -> rch -> fa = root;
}
if(root) update(root);
recycle_bin[++top] = cur;
}
};
class segtree
{
public:
Splay node;
int l, r, lch, rch;
void modify(int pre_val, int new_val)
{
node.del(pre_val, node.root);
node.insert(new_val, node.root, NULL);
}
};
segtree t[Maxn * 4];
int v[Maxn];
void seg_build(int l, int r, int p)
{
t[p].node.resize(2 * (r - l + 1));
t[p].l = l, t[p].r = r;
t[p].node.build(&v[l], r - l + 1);
if(l == r)
{
t[p].lch = t[p].rch = 0;
return;
}
t[p].lch = p << 1;
t[p].rch = p << 1 | 1;
int mid = l + r >> 1;
seg_build(l, mid, p << 1);
seg_build(mid + 1, r, p << 1 | 1);
}
int Query(int l, int r, int p, int v)
{
if(t[p].l == l && t[p].r == r)
{
return t[p].node.Query(v, t[p].node.root);
}
else
{
int mid = t[p].l + t[p].r >> 1;
if(r <= mid)
{
return Query(l, r, p << 1, v);
}
else if(l > mid)
{
return Query(l, r, p << 1 | 1, v);
}
else
{
return Query(l, mid, p << 1, v) + Query(mid + 1, r, p << 1 | 1, v);
}
}
}
void seg_modify(int pos, int new_val)
{
int p = 1;
int mid;
do
{
t[p].modify(v[pos], new_val);
mid = t[p].l + t[p].r >> 1;
if(pos <= mid) p = t[p].lch;
else p = t[p].rch;
}while(p);
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n, m, x, y, z;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &v[i]);
seg_build(1, n, 1);
for(int i = 0; i < m; ++i)
{
char o;
while(o = getchar(), o != 'Q' && o != 'C');
if(o == 'Q')
{
scanf("%d%d%d", &x, &y, &z);
--z;
int l = 0, r = 1000000010, mid;
while(l <= r)
{
mid = l + r >> 1;
int s = Query(x, y, 1, mid);
if(s > z)
{
if(Query(x, y, 1, mid - 1) <= z)
{
printf("%d\n", mid - 1);
break;
}
r = mid - 1;
}
else
{
l = mid + 1;
}
}
}
else
{
scanf("%d%d", &x, &y);
seg_modify(x, y);
v[x] = y;
}
}
return 0;
}