ZOJ_2112

    当自己学了splay之后,这个题目的基本思想就可以理解了,但代码还是写得相当挫,在后面的学习过程中再不断完善吧。

    首先线段树可以完成对区间的限制,而平衡树则可以完成统计区间上不大于x的数,这样我们就可以在线段树的节点上放一棵平衡树,平衡树上有这个区间上所有的数。修改操作比较好完成,只要查找这个数在哪些区间中,并在对应的平衡树中更新相应的值即可。至于查询操作,我们可以先二分答案x,将问题转化成x是否可以作为第k大的数,然后只要统计区间中不大于x的数的数量n2,以及不大于x-1的数的数量n1,如果满足n1<k<=n2,那么自然x就是解了。

    由于线段树有logn层,每层的平衡树至多会使用n个节点,因为如果这个区间包含越界的元素,我们完全可以不建立这个平衡树,因为在访问区间的时候一定不会访问到这个区间,这样空间复杂度就是O(nlogn)。

#include<stdio.h>
#include<string.h>
#define MAXD 50010
#define MAXS 1000010
#define INF 0x3f3f3f3f
int N, Q, M, top, pool[MAXS], node, key[MAXS], left[MAXS], right[MAXS], size[MAXS], pre[MAXS], a[2 * MAXD], lx[4 * MAXD], rx[4 * MAXD];
struct Splay
{
int T;
void update(int x)
{
size[x] = size[left[x]] + size[right[x]] + 1;
}
void left_rotate(int x)
{
int y = right[x], p = pre[x];
right[x] = left[y];
if(right[x])
pre[right[x]] = x;
left[y] = x;
pre[x] = y;
pre[y] = p;
if(p != 0)
right[p] == x ? right[p] = y : left[p] = y;
else
T = y;
update(x);
}
void right_rotate(int x)
{
int y = left[x], p = pre[x];
left[x] = right[y];
if(left[x])
pre[left[x]] = x;
right[y] = x;
pre[x] = y;
pre[y] = p;
if(p != 0)
right[p] == x ? right[p] = y : left[p] = y;
else
T = y;
update(x);
}
void splay(int x, int goal)
{
int y, z;
for(;;)
{
if((y = pre[x]) == goal)
break;
if((z = pre[y]) == goal)
right[y] == x ? left_rotate(y) : right_rotate(y);
else
{
if(right[z] == y)
{
if(right[y] == x)
left_rotate(z), left_rotate(y);
else
right_rotate(y), left_rotate(z);
}
else
{
if(left[y] == x)
right_rotate(z), right_rotate(y);
else
left_rotate(y), right_rotate(z);
}
}
}
update(x);
}
int calculate(int &T, int k)
{
if(T == 0)
return 0;
if(k < key[T])
return calculate(left[T], k);
else
return size[left[T]] + 1 + calculate(right[T], k);
}
int Delete(int &T, int v)
{
-- size[T];
if(key[T] == v || (v < key[T] && left[T] == 0) || (v > key[T] && right[T] == 0))
{
int k = key[T], p = pre[T];
if(left[T] == 0 || right[T] == 0)
{
pool[++ top] = T;
T = left[T] + right[T];
if(T)
pre[T] = p;
}
else
key[T] = Delete(left[T], key[T] + 1);
return k;
}
if(v < key[T])
return Delete(left[T], v);
else
return Delete(right[T], v);
}
int query(int k)
{
return calculate(left[right[T]], k);
}
void change(int k, int v)
{
Delete(T, k);
splay(Insert(T, v, 0), right[T]);
}
void new_node(int &T, int v)
{
if(top)
T = pool[top --];
else
T = ++ node;
key[T] = v;
size[T] = 1;
left[T] = right[T] = 0;
}
int Insert(int &T, int v, int fa)
{
if(T == 0)
{
new_node(T, v);
pre[T] = fa;
return T;
}
++ size[T];
if(v < key[T])
return Insert(left[T], v, T);
else
return Insert(right[T], v, T);
}
void init(int x, int y)
{
int i, j, k;
T = 0;
new_node(T, -INF), new_node(right[T], INF);
pre[T] = 0, pre[right[T]] = T;
size[T] = 2;
for(i = x; i <= y; i ++)
splay(Insert(T, a[i], 0), right[T]);
}
}sp[4 * MAXD];
void init()
{
int i, j, k;
for(M = 1; M < N + 2; M <<= 1);
node = top = size[0] = left[0] = right[0] = 0;
memset(a, 0, sizeof(a[0]) * M);
for(i = 1; i <= N; i ++)
scanf("%d", &a[i]);
for(i = M; i < 2 * M; i ++)
{
lx[i] = rx[i] = i - M;
if(lx[i] >= 1 && rx[i] <= N)
sp[i].init(lx[i], rx[i]);
}
for(i = M - 1; i > 1; i --)
{
lx[i] = lx[2 * i], rx[i] = rx[2 * i + 1];
if(lx[i] >= 1 && rx[i] <= N)
sp[i].init(lx[i], rx[i]);
}
}
void change(int x, int k)
{
int i;
for(i = M + x; i ^ 1; i >>= 1)
{
if(lx[i] >= 1 && rx[i] <= N)
sp[i].change(a[x], k);
}
a[x] = k;
}
void query(int x, int y, int k)
{
int i, j, min, max, mid, n1, n2;
min = 0, max = INF;
for(;;)
{
mid = (min + max) / 2;
if(mid == min)
break;
n1 = n2 = 0;
for(i = x + M - 1, j = y + M + 1; i ^ j ^ 1; i >>= 1, j >>= 1)
{
if(~i & 1)
{
n1 += sp[i ^ 1].query(mid - 1), n2 += sp[i ^ 1].query(mid);
}
if(j & 1)
n1 += sp[j ^ 1].query(mid - 1), n2 += sp[j ^ 1].query(mid);
}
if(n1 >= k)
max = mid;
else
min = mid;
}
printf("%d\n", mid);
}
void solve()
{
int i, j, k, x, y;
char b[5];
for(i = 0; i < Q; i ++)
{
scanf("%s", b);
if(b[0] == 'Q')
{
scanf("%d%d%d", &x, &y, &k);
query(x, y, k);
}
else
{
scanf("%d%d", &x, &k);
change(x, k);
}
}
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
scanf("%d%d", &N, &Q);
init();
solve();
}
return 0;
}


posted on 2012-03-22 17:36  Staginner  阅读(754)  评论(0编辑  收藏  举报