【模拟试题】逛公园
Description
窝窝头经常陪碳原子去公园玩,也就是所谓的遛狗啦…在窝窝头家附近有一条“公园路”,路的一边从南到北依次排着n个公园,碳原子早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,碳原子就根据公园的风景给每个公园打了分-.-。窝窝头为了省事,每次遛狗的时候都会事先规定一个范围,碳原子只可以在第a个和第b个公园之间(包括a、b两个公园)选择得分第k大的公园玩。同时,由于一些公园的景观会有所改变,所以,碳原子的打分也可能会有一些变化。
那么,就请你来帮碳原子选择公园吧。
一开始,碳原子就根据公园的风景给每个公园打了分-.-。窝窝头为了省事,每次遛狗的时候都会事先规定一个范围,碳原子只可以在第a个和第b个公园之间(包括a、b两个公园)选择得分第k大的公园玩。同时,由于一些公园的景观会有所改变,所以,碳原子的打分也可能会有一些变化。
那么,就请你来帮碳原子选择公园吧。
Input
第一行,两个整数N和M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来N行,每行一个整数,依次给出碳原子开始时对公园的打分。
接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,窝窝头要带碳原子出去玩,接下来的3个整数a,b和k给出了选择公园的范围,窝窝头想知道a到b这些公园中得分第k大的公园的得分是哪个;K=2表示,碳原子改变了对某个公园的打分,接下来的两个整数p和s,表示碳原子对第p个公园的打分变成了s(1≤p≤N)。
接下来N行,每行一个整数,依次给出碳原子开始时对公园的打分。
接下来M行,每行三个整数。第一个整数K,1或2。K=1表示,窝窝头要带碳原子出去玩,接下来的3个整数a,b和k给出了选择公园的范围,窝窝头想知道a到b这些公园中得分第k大的公园的得分是哪个;K=2表示,碳原子改变了对某个公园的打分,接下来的两个整数p和s,表示碳原子对第p个公园的打分变成了s(1≤p≤N)。
Output
碳原子每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分第k大的值。
Sample Input
5 3
1 2 -3 4 5
1 1 5 3
2 3 -1
1 1 3 2
Sample Output
2
1
Hint
park.in
5 4
2 1 5 4 3
1 1 5 3
1 1 3 1
2 1 4
1 1 3 2
park.out
3
5
4
【数据范围】
对于10%的数据,1<=N,M<=1000
对于30%的数据,1<=N,M<=20000
对于100%的数据,1<=N,M<=100000,0<=|某个公园的得分|<=N,K=1或2, 1<=a<=b<=N,1<=p<=N,1<=k<=b-a+1
5 4
2 1 5 4 3
1 1 5 3
1 1 3 1
2 1 4
1 1 3 2
park.out
3
5
4
【数据范围】
对于10%的数据,1<=N,M<=1000
对于30%的数据,1<=N,M<=20000
对于100%的数据,1<=N,M<=100000,0<=|某个公园的得分|<=N,K=1或2, 1<=a<=b<=N,1<=p<=N,1<=k<=b-a+1
Solution
带修改的区间第k大,用主席树试一下。
CODE
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1000005;
inline int read(){
char c;int rec=0,f=1;
while((c=getchar())<'0'||c>'9')if(c=='-')f=-1;
while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
return rec*f;
}
int n,m,val[N];
int root[N],cnt,llen,rlen,len[2];
struct Presistent_Segtree{int F,s[2],cnt;}tree[N*20];
int V[2][N];
inline int lowbit(int x){return x&-x;}
inline int Add(int val,int L,int R,int pos,int f){
if(pos==0)pos=++cnt;
tree[pos].cnt+=f;
if(L==R)return pos;
int mid=(L+R)>>1;
if(mid>=val)tree[pos].s[0]=Add(val,L,mid,tree[pos].s[0],f);
else tree[pos].s[1]=Add(val,mid+1,R,tree[pos].s[1],f);
return pos;
}
inline void Insert(int x,int val,int f){
while(x<=n){
root[x]=Add(val,0,2*N,root[x],f);
x+=lowbit(x);
}return ;
}
inline int Get_Pos(int x,int f){
int c=0,i;
for(i=x;i>=1;i-=lowbit(i))V[f][++c]=root[i];
return c;
}
int Get_sum(int f){
int i,sum=0;
for(i=1;i<=len[f];i++)
sum+=tree[tree[V[f][i]].s[0]].cnt;
return sum;
}
inline int Ask(int x,int y,int Left,int Right,int k){
if(Left==Right) return Left;
int p=Get_sum(1)-Get_sum(0),i,mid=(Left+Right)/2;
if(k<=p) {
for(i=1;i<=len[0];i++) V[0][i]=tree[V[0][i]].s[0];
for(i=1;i<=len[1];i++) V[1][i]=tree[V[1][i]].s[0];
return Ask(x,y,Left,mid,k);
}
else {
for(i=1;i<=len[0];i++) V[0][i]=tree[V[0][i]].s[1];
for(i=1;i<=len[1];i++) V[1][i]=tree[V[1][i]].s[1];
return Ask(x,y,mid+1,Right,k-p);
}
}
int main(){
n=read();m=read();
int i,f,x,y;
for(i=1;i<=n;i++)val[i]=read(),val[i]+=N;
for(i=1;i<=n;i++)Insert(i,val[i],1);
for(i=1;i<=m;i++){
f=read();
if(f==1){
x=read();y=read();f=read();f=(y-x+1)-f+1;
len[0]=Get_Pos(x-1,0);len[1]=Get_Pos(y,1);
cout<<Ask(x-1,y,0,2*N,f)-N<<'\n';
}
else if(f==2){
x=read();Insert(x,val[x],-1);
val[x]=read();val[x]+=N;Insert(x,val[x],1);
}
}
return 0;
}