ZOJ2112(区间动态求第K大)

本文介绍了一个动态排名问题的解决方法,使用Treap数据结构来高效处理数组元素的更新与查询操作,支持快速查找区间内第K小的元素及元素值的修改。

题目:Dynamic Rankings

 

题意:

N<=50000 M<=10000,给定一个数组A[1]~A[N],有M个操作

每个操作可以如下

Q i j t 输出 A[I]~A[J]之间第t小的数

C i t 将A[I]赋值为t

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;

#define N 60010
#define M 10010
#define INF 1000000000

char ctrl[M][3];
int cnt,n,m;
int P[M],Q[M],a[N],b[N],K[M];

struct treap
{
   int key,wei,cnt,size,ch[2];
}T[N * 15];

int tree[N << 1],nodecnt,root;

void init()
{
   T[0].size = 0;
   T[0].wei = -INF;
   nodecnt = root = 0;
}

int ID(int l,int r)
{
    return l + r | l != r;
}

void update(int x)
{
   T[x].size = T[T[x].ch[0]].size + T[T[x].ch[1]].size + T[x].cnt;
}

void rotate(int &x,int t)
{
   int y = T[x].ch[t];
   T[x].ch[t] = T[y].ch[!t];
   T[y].ch[!t] = x;
   update(x);
   update(y);
   x = y;
}

void insert(int &x,int t)
{
   if (!x)
   {
       x = ++ nodecnt;
       T[x].key = t;
       T[x].wei = rand();
       T[x].cnt = 1;
       T[x].ch[0] = T[x].ch[1] = 0;
   }
   else if (T[x].key == t)
       T[x].cnt ++;
   else
   {
       int k = T[x].key < t;
       insert(T[x].ch[k],t);
       if (T[x].wei < T[T[x].ch[k]].wei)
           rotate(x,k);
   }
   update(x);
}

void erase(int &x,int t)
{
   if (T[x].key == t)
   {
       if (T[x].cnt == 1)
       {
           if (!T[x].ch[0] && !T[x].ch[1])
           {
               x = 0;
               return;
           }
           rotate(x,T[T[x].ch[0]].wei < T[T[x].ch[1]].wei);
           erase(x,t);
       }
       else T[x].cnt--;
   }
   else
       erase(T[x].ch[T[x].key < t],t);
   update(x);
}

int select(int x,int t)
{
   if (!x) return 0;
   if (T[x].key > t) return select(T[x].ch[0],t);
   return T[x].cnt + T[T[x].ch[0]].size + select(T[x].ch[1],t);
}

void treeins(int l,int r,int i,int x)
{
   insert(tree[ID(l,r)],x);
   if (l == r) return;
   int m = l + r >> 1;
   if (i <= m) treeins(l,m,i,x);
   else treeins(m + 1,r,i,x);
}

void treedel(int l,int r,int i,int x)
{
   erase(tree[ID(l,r)],x);
   if (l == r) return;
   int m = l + r >> 1;
   if (i <= m) treedel(l,m,i,x);
   else treedel(m + 1,r,i,x);
}

int query(int l,int r,int x,int y,int t)
{
   if (l == r) return l;
   int m = l + r >> 1;
   int ans = select(tree[ID(l,m)],y) - select(tree[ID(l,m)],x);
   if (ans >= t) return query(l,m,x,y,t);
   return query(m + 1,r,x,y,t - ans);
}

int main()
{
   int Times;
   scanf("%d",&Times);
   while (Times --)
   {
       scanf("%d%d",&n,&m);
       memset(tree,0,sizeof tree);
       init();
       cnt = 0;
       for (int i = 1;i <= n;i ++)
           scanf("%d",&a[i]),b[++ cnt] = a[i];
       for (int i = 1;i <= m;i ++)
       {
           scanf("%s%d%d",ctrl[i],&P[i],&Q[i]);
           if (ctrl[i][0] == 'Q')
               scanf("%d",&K[i]);
           else
               b[++ cnt] = Q[i];
       }
       sort(b + 1,b + 1 + cnt);
       cnt = unique(b + 1,b + 1 + cnt) - b - 1;
       for (int i = 1;i <= n;i ++)
       {
           a[i] = lower_bound(b + 1,b + 1 + cnt,a[i]) - b;
           treeins(1,cnt,a[i],i);
       }
       for(int i = 1;i <= m;i ++)
       {
           if (ctrl[i][0] == 'Q')
           {
               int id = query(1,cnt,P[i] - 1,Q[i],K[i]);
               printf("%d\n",b[id]);
           }
           else
           {
               treedel(1,cnt,a[P[i]],P[i]);
               a[P[i]] = lower_bound(b + 1,b + 1 + cnt,Q[i]) - b;
               treeins(1,cnt,a[P[i]],P[i]);
           }
       }
   }
   return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值