动态排名系统 20
[问题描述]
给定一个长度为 N 的已知序列 A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:
1、查询 A[i],A[i+1],A[i+2],...,A[j](1<=i<=j<=N)中,升序排列后排名第 k 的数。
2、修改 A[i]的值为 j。
所谓排名第 k,指一些数按照升序排列后,第 k 位的数。例如序列{6,1,9,6,6},排名第 3 的数
是 6,排名第 5 的数是 9。
[输入格式]
第一行包含一个整数 D(0<=D<=4),表示测试数据的数目。接下来有 D 组测试数据,每组测
试数据中,首先是两个整数 N(1<=N<=50000),M(1<=M<=10000),表示序列的长度为 N,有 M
个操作。接下来的 N 个不大于 1,000,000,000 正整数,第 i 个表示序列 A[i]的初始值。然后的
M 行,每行为一个操作
Q i j k 或者
C i j
分别表示查询 A[i],A[i+1],A[i+2],...,A[j](1<=i<=j<=N)中,升序排列后排名第 k 的数,和修改 A[i]
的值为 j。
[输出格式]
对于每个查询,输出一行整数,为查询的结果。测试数据之间不应有空行。
题解:方法很多,可用可持久化数据结构来做。
暂时只会线段树套平衡树+二分的方法,复杂度O(n*lgn*lgn*lgn)。
代码如下:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<string.h>
#include<vector>
#define nn 50010
#define mod 100003
typedef long long LL;
typedef unsigned long long LLU;
using namespace std;
struct node
{
int val;
int key;
int num;
int treenum;
node* son[2];
};
void update(node *id)
{
if(id==NULL)
return ;
id->treenum=id->num;
for(int i=0;i<=1;i++)
{
if(id->son[i]!=NULL)
{
id->treenum+=id->son[i]->treenum;
}
}
}
void Rotate(node* &id,int d)
{
node* tem=id->son[d];
id->son[d]=tem->son[d^1];
tem->son[d^1]=id;
update(id);
update(tem);
id=tem;
}
void Insert(node* &id,int val)
{
if(id==NULL)
{
id=new node;
id->val=val;
id->key=rand()*rand();
id->num=1;
id->treenum=1;
id->son[0]=id->son[1]=NULL;
return ;
}
if(id->val==val)
{
id->num++;
update(id);
}
else if(val<id->val)
{
Insert(id->son[0],val);
update(id);
if(id->son[0]->key<id->key)
{
Rotate(id,0);
}
}
else
{
Insert(id->son[1],val);
update(id);
if(id->son[1]->key<id->key)
{
Rotate(id,1);
}
}
}
void Delete(node* &id,int val)
{
if(id==NULL)
return ;
if(val==id->val)
{
if(id->num==1)
{
if(id->son[0]==NULL)
{
node *k=id;
id=id->son[1];
delete k;
}
else if(id->son[1]==NULL)
{
node *k=id;
id=id->son[0];
delete k;
}
else if(id->son[0]->key<id->son[1]->key)
{
Rotate(id,0);
Delete(id->son[1],val);
}
else
{
Rotate(id,1);
Delete(id->son[0],val);
}
}
else
{
id->num--;
}
}
else if(val<id->val)
Delete(id->son[0],val);
else
Delete(id->son[1],val);
update(id);
}
int ask(node* id,int val,pair<int,int>&tem)
{
if(id==NULL)
return 0;
if(id->val>=val)
{
if(id->val<tem.first)
{
tem=make_pair(id->val,id->num);
}
else if(id->val==tem.first)
{
tem.second+=id->num;
}
return ask(id->son[0],val,tem);//???
}
else
{
int re=id->num;
if(id->son[0]!=NULL)
re+=id->son[0]->treenum;
return re+ask(id->son[1],val,tem);
}
}
void Clear(node* id)
{
if(id==NULL)
return ;
Clear(id->son[0]);
Clear(id->son[1]);
delete id;
}
node* Stree[132000];
int n,m,a[nn];
void build(int id,int l,int r)
{
Stree[id]=NULL;
for(int i=l;i<=r;i++)
Insert(Stree[id],a[i]);
if(l==r)
return ;
int mid=(l+r)/2;
build(2*id,l,mid);
build(2*id+1,mid+1,r);
}
void Change(int id,int l,int r,int wei,int val)
{
Delete(Stree[id],a[wei]);
Insert(Stree[id],val);
if(l==r)
{
return ;
}
int mid=(l+r)/2;
if(wei<=mid)
Change(2*id,l,mid,wei,val);
else
Change(2*id+1,mid+1,r,wei,val);
}
int ve[nn],lv;
void Check(int id,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
ve[lv++]=id;
return ;
}
int mid=(l+r)/2;
if(L<=mid)
Check(2*id,l,mid,L,R);
if(R>mid)
Check(2*id+1,mid+1,r,L,R);
}
int solve(int l,int r,int k)
{
int i=0;
int j=1000000000;
int mid;
pair<int,int>tem;
int ix,e;
lv=0;
Check(1,1,n,l,r);
while(i<=j)
{
tem=make_pair(1000000001,-1);
mid=(i+j)/2;
ix=0;
for(e=0;e<lv;e++)
{
ix+=ask(Stree[ve[e]],mid,tem);
}
if(tem.second==-1)
{
j=mid-1;
continue;
}
if(ix+1<=k&&k<=ix+tem.second)
{
return tem.first;
}
if(k<ix+1)
{
j=mid-1;
}
else
i=mid+1;
}
return -1;
}
void Clear2(int id,int l,int r)
{
Clear(Stree[id]);
if(l==r)
return ;
int mid=(l+r)/2;
Clear2(2*id,l,mid);
Clear2(2*id+1,mid+1,r);
}
int main()
{
int t,i;
char s[5];
int l,r,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build(1,1,n);
while(m--)
{
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",solve(l,r,k));
}
else
{
scanf("%d%d",&l,&r);
Change(1,1,n,l,r);
a[l]=r;
}
}
Clear2(1,1,n);
}
return 0;
}