[问题描述]
给定一个长度为N的已知序列Ai,要求维护这个序列,能够支持以下两种操作:
1、查询A[i],A[i+1],A[i+2],…,Aj中,升序排列后排名第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],…,Aj中,升序排列后排名第k的数,和修改A[i]的值为j。
[输出格式]
对于每个查询,输出一行整数,为查询的结果。测试数据之间不应有空行。
[样例输入]
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
[样例输出]
3
6
3
6
一开始线段树乱搞,写了个错误性很显然的代码交上去还以为没问题
结果就是这么显然的错误竟然能A5个点2333
后来受了启发做了两个改变就A了.
1.把修改操作在读入时拆分成两个操作,一个是删除,一个是插入(核心就是这个位置.其实线段树乱搞加上这一步也可以A的)
2.把线段树改成了树状数组简洁好看www
我的整体二分也算是写熟了>w<
//AC code by CreationAugust
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100010
#define MAXINT 0x7fffffff
#define lowbit(x) x&-x
using namespace std;
int T;
int n,m;
int ans[MAXN];
int a[MAXN],last[MAXN];
char ch[2];
int c[MAXN];
int top=0,num=0,l,r,k;
struct Query
{
int l,r,x,op,k;
}ques[MAXN],q1[MAXN],q2[MAXN];
void add(int i,int x)
{
while (i>0&&i<=num) c[i]+=x,i+=lowbit(i);
}
int sum(int l,int r)
{
int ret=0;
while (r>0) ret+=c[r],r-=lowbit(r);
while (l>0) ret-=c[l],l-=lowbit(l);
return ret;
}
void solve(int L,int R,int l,int r)
{
int mid=(L+R)>>1,tp1=0,tp2=0;
if (l>r) return;
if (L==R)
{
for (int i=l;i<=r;i++) if (ques[i].op==2) ans[ques[i].x]=a[mid];
return;
}
for (int i=l;i<=r;i++)
{
if (ques[i].op==1)
{
if (ques[i].k<=a[mid]) add(ques[i].l,ques[i].r),q1[++tp1]=ques[i];
else q2[++tp2]=ques[i];
}
else
{
int temp=sum(ques[i].l-1,ques[i].r);
if (ques[i].k<=temp) q1[++tp1]=ques[i];
else ques[i].k-=temp,q2[++tp2]=ques[i];
}
}
for (int i=1;i<=tp1;i++) if (q1[i].op==1) add(q1[i].l,-q1[i].r);
memcpy(ques+l,q1+1,sizeof(Query)*tp1);
memcpy(ques+l+tp1,q2+1,sizeof(Query)*tp2);
solve(L,mid,l,l+tp1-1);
solve(mid+1,R,l+tp1,r);
}
int main()
{
freopen("dynrank.in","r",stdin);
freopen("dynrank.out","w",stdout);
scanf("%d",&T);
while (T--)
{
memset(ans,0,sizeof(ans));
Query temp[MAXN];
top=0;num=0;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[++top]);last[top]=a[top];
ques[++num]=((Query){i,1,i,1,a[top]});
}
for (int i=n+1;i<=n+m;i++)
{
scanf("%s",ch);
if (ch[0]=='Q')
{
scanf("%d%d%d",&l,&r,&k);
ques[++num]=((Query){l,r,num,2,k});
}
else
{
scanf("%d%d",&l,&k);a[++top]=k;
ques[++num]=((Query){l,1,num,1,k});//将一个修改操作拆分成一个删除,一个插入
ques[++num]=((Query){l,-1,num,1,last[l]});
last[l]=k;
}
}
sort(a+1,a+top+1);
top=unique(a+1,a+top+1)-a-1;
for (int i=1;i<=num;i++) temp[i]=ques[i];
solve(1,top,1,num);
for (int i=1;i<=num;i++) if (temp[i].op!=1) printf("%d\n",ans[i]);
}
}