P2617 Dynamic Rankings-动态主席树
程序员文章站
2024-03-02 21:59:04
...
题目描述
给定一个含有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继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。
对于每一个询问指令,你必须输出正确的回答。
输入输出格式
输入格式:
第一行有两个正整数n(1≤n≤100000),m(1≤m≤100000)。分别表示序列的长度和指令的个数。
第二行有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。
输出格式:
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。
输入输出样例
输入样例#1:
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
输出样例#1:
3
6
说明
10%的数据中,m,n≤100;
20%的数据中,m,n≤1000;
50%的数据中,m,n≤10000。
对于所有数据,m,n≤100000
请注意常数优化,但写法正常的整体二分和树套树都可以以大约1000ms每个点的时间过。
来源:bzoj1901
本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。
题解:动态主席树查询区间第k小
#include<bits/stdc++.h>
#define begin b+1
#define end b+1+size
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int b[maxn+maxn];
int ca[maxn],cb[maxn],cc[maxn];
int xx[maxn],yy[maxn];
int size=0,cnt=0;
int root[maxn];
int t0,t1;
struct node{
int l,r,sum;
}sz[maxn*400];//动态开 400倍
void updata(int l,int r,int &x,int y,int v,int pos)//建树
{
if(x==0) x=++cnt;
sz[x]=sz[y];
sz[x].sum+=v;
if(l==r) return ;
int mid=(l+r)>>1;
if(mid>=pos) updata(l,mid,sz[x].l,sz[y].l,v,pos);
else updata(mid+1,r,sz[x].r,sz[y].r,v,pos);
}
int getSum(int l,int r,int k)
{
if(l==r) return l;
int mid=(l+r)>>1,ans=0;
for(int i=1;i<=t0;i++) ans-=sz[sz[xx[i]].l].sum;
for(int i=1;i<=t1;i++) ans+=sz[sz[yy[i]].l].sum;
if(ans>=k)
{
for(int i=1;i<=t0;i++) xx[i]=sz[xx[i]].l;
for(int i=1;i<=t1;i++) yy[i]=sz[yy[i]].l;
return getSum(l,mid,k);
}
else{
for(int i=1;i<=t0;i++) xx[i]=sz[xx[i]].r;
for(int i=1;i<=t1;i++) yy[i]=sz[yy[i]].r;
return getSum(mid+1,r,k-ans);
}
}
int low_bit(int x)
{
return x&(-x);
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[++size]=a[i];
}
for(int i=1;i<=m;i++)
{
char q[2];
scanf("%s",q);
if(q[0]=='Q')
{
scanf("%d %d %d",&ca[i],&cb[i],&cc[i]);
}
else
{
scanf("%d %d",&ca[i],&cb[i]);
b[++size]=cb[i];
}
}
sort(b+1,b+1+size);//去重,离散化
size=unique(b+1,b+1+size)-b-1;
for(int i=1;i<=n;i++)
{
int p=lower_bound(b+1,b+1+size,a[i])-b;//查询其位置
for(int j=i;j<=n;j+=low_bit(j))//树状数组维护
{
updata(1,size,root[j],root[j],1,p);
}
}
for(int i=1;i<=m;i++)
{
if(cc[i]==0)
{
int p=lower_bound(b+1,b+1+size,a[ca[i]])-b;
for(int j=ca[i];j<=n;j+=low_bit(j))
{
updata(1,size,root[j],root[j],-1,p);
}
a[ca[i]]=cb[i];
p=lower_bound(b+1,b+1+size,a[ca[i]])-b;
for(int j=ca[i];j<=n;j+=low_bit(j))
{
updata(1,size,root[j],root[j],1,p);
}
}
else
{
t0=0;
t1=0;
for(int j=ca[i]-1;j>0;j-=low_bit(j))
{
xx[++t0]=root[j];
}
for(int j=cb[i];j>0;j-=low_bit(j))
{
yy[++t1]=root[j];
}
printf("%d\n",b[getSum(1,size,cc[i])]);
}
}
}