BZOJ1901: Zju2112 Dynamic Rankings
题解:很显然的树套树 主席树+树状数组 动态维护区间权值 然后类似于查询区间第K大 复杂度nlog^2n 空间也如此
#include <bits/stdc++.h>
const int MAXN=2e4+10;
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
typedef struct node{
int l,r,sum;
}node;
node d[MAXN*201];
int rt[MAXN];
int cnt;
int get_id(int x){return x&(-x);}
void update(int &x,int y,int l,int r,int t,int vul){
x=++cnt;d[x]=d[y];d[x].sum+=vul;
if(l==r)return ;
int mid=(l+r)>>1;
if(t<=mid)update(d[x].l,d[y].l,l,mid,t,vul);
else update(d[x].r,d[y].r,mid+1,r,t,vul);
}
int ans,sum;
vector<int>v1;
vector<int>v2;
void querty(int l,int r,int k){
if(l==r){ans=l;return ;}
sum=0;
int mid=(l+r)>>1;
for(int i=0;i<v1.size();i++)sum+=d[d[v1[i]].l].sum;
for(int i=0;i<v2.size();i++)sum-=d[d[v2[i]].l].sum;
// cout<<l<<" "<<r<<" "<<sum<<endl;
if(k<=sum){
for(int i=0;i<v1.size();i++)v1[i]=d[v1[i]].l;
for(int i=0;i<v2.size();i++)v2[i]=d[v2[i]].l;
querty(l,mid,k);
}
else{
for(int i=0;i<v1.size();i++)v1[i]=d[v1[i]].r;
for(int i=0;i<v2.size();i++)v2[i]=d[v2[i]].r;
querty(mid+1,r,k-sum);
}
}
vector<int>vec;
int a[MAXN];
typedef struct Q{
int op,l,r,k;
}Q;
Q q[MAXN];
int main(){
int n,m;n=read();m=read();
for(int i=1;i<=n;i++)a[i]=read(),vec.push_back(a[i]);
char ch;
for(int i=1;i<=m;i++){
scanf(" %c",&ch);
if(ch=='Q'){q[i].op=1;q[i].l=read();q[i].r=read();q[i].k=read();}
else{q[i].op=2;q[i].l=read();q[i].r=read();vec.push_back(q[i].r);}
}
sort(vec.begin(),vec.end());
int sz=unique(vec.begin(),vec.end())-vec.begin();
for(int i=1;i<=n;i++){
a[i]=lower_bound(vec.begin(),vec.begin()+sz,a[i])-vec.begin()+1;
// cout<<a[i]<<" ";
for(int j=i;j<=n;j+=get_id(j))update(rt[j],rt[j],1,sz,a[i],1);
// cout<<endl;
}
// cout<<endl;
for(int i=1;i<=m;i++){
if(q[i].op==2){
q[i].r=lower_bound(vec.begin(),vec.begin()+sz,q[i].r)-vec.begin()+1;
for(int j=q[i].l;j<=n;j+=get_id(j))update(rt[j],rt[j],1,sz,a[q[i].l],-1),update(rt[j],rt[j],1,sz,q[i].r,1);
a[q[i].l]=q[i].r;
}
else{
v1.clear();v2.clear();
// cout<<q[i].l<<" "<<q[i].r<<" "<<q[i].k<<endl;
for(int j=q[i].r;j>0;j-=get_id(j))v1.push_back(rt[j]);
// cout<<endl;
for(int j=q[i].l-1;j>0;j-=get_id(j))v2.push_back(rt[j]);
// cout<<endl;
querty(1,sz,q[i].k);
printf("%d\n",vec[ans-1]);
}
}
return 0;
}
1901: Zju2112 Dynamic Rankings
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 9085 Solved: 3802
[Submit][Status][Discuss]
Description
给定一个含有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继续回答上面的问题。
Input
第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。
分别表示序列的长度和指令的个数。
第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。
接下来的m行描述每条指令
每行的格式是下面两种格式中的一种。
Q i j k 或者 C i t
Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)
表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t
m,n≤10000
Output
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
Sample Input
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
6

浙公网安备 33010602011771号