题目描述
传送门
题目大意:给定一个含有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继续回答上面的问题。
题解
其实这道题就是带修改的主席树。。。
将询问离线,对于所有出现的权值离散化。
然后外层的树状数组维护位置,内层的线段树以权值为下标。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 20003
#define M 5000000
using namespace std;
struct data{
int ls,rs,sum;
}tr[M];
int n,m,a[N],sz,q1[N],b[N],q2[N],cnt,cnt1,cnt2,root[N],mp[N];
struct node{
int opt,x,y,k;
}q[N];
int lowbit(int x)
{
return x&(-x);
}
void pointchange(int &i,int l,int r,int x,int val)
{
if (!i) i=++sz;
tr[i].sum+=val;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) pointchange(tr[i].ls,l,mid,x,val);
else pointchange(tr[i].rs,mid+1,r,x,val);
}
void change(int x,int y,int val)
{
for (int i=x;i<=n;i+=lowbit(i))
pointchange(root[i],1,cnt,y,val);
}
int find(int l,int r,int k)
{
if (l==r) return l;
int sum=0; int mid=(l+r)/2;
for (int i=1;i<=cnt1;i++)
sum+=tr[tr[q1[i]].ls].sum;
for (int i=1;i<=cnt2;i++)
sum-=tr[tr[q2[i]].ls].sum;
if (k<=sum) {
for (int i=1;i<=cnt1;i++) q1[i]=tr[q1[i]].ls;
for (int i=1;i<=cnt2;i++) q2[i]=tr[q2[i]].ls;
return find(l,mid,k);
}
else {
for (int i=1;i<=cnt1;i++) q1[i]=tr[q1[i]].rs;
for (int i=1;i<=cnt2;i++) q2[i]=tr[q2[i]].rs;
return find(mid+1,r,k-sum);
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
cnt=n;
for (int i=1;i<=m;i++) {
char s[3]; int x,y,k;
scanf("%s%d%d",s+1,&x,&y);
if (s[1]=='Q') {
scanf("%d",&k);
q[i].opt=1; q[i].x=x; q[i].y=y;
q[i].k=k;
}
else {
q[i].opt=0; q[i].x=x; q[i].y=y;
b[++cnt]=y;
}
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for (int i=1;i<=cnt;i++) mp[i]=b[i];
for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
for (int i=1;i<=m;i++)
if (!q[i].opt) q[i].y=lower_bound(b+1,b+cnt+1,q[i].y)-b;
for (int i=1;i<=n;i++) change(i,a[i],1);
for (int i=1;i<=m;i++) {
if (!q[i].opt) {
int x=q[i].x;
change(x,a[x],-1);
a[x]=q[i].y; change(x,a[x],1);
}
else {
cnt1=0,cnt2=0;
for (int j=q[i].y;j>=1;j-=lowbit(j)) q1[++cnt1]=root[j];
for (int j=q[i].x-1;j>=1;j-=lowbit(j)) q2[++cnt2]=root[j];
int t=find(1,cnt,q[i].k); //cout<<t<<endl;
printf("%d\n",mp[t]);
}
}
}