detect
2019-07-25 18:37:41
经过实测,大概只能过50000的样子。
分成sqrt(n)块, 块的大小为sqrt(n),块内维护有序数列。 修改就暴力重构块,显然不会超时
对于每一个询问,先二分一个区间权值(发现这道题是1~1e9),然后去统计所求的区间内小于这个数的个数有多少。对于两边不完整的块暴力统计,对于完整的块,则二分查找最小的~~数,即可在log时间内得到答案。
#include<bits/stdc++.h>
using namespace std;
int getint()
{
int summ=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
summ=(summ<<3)+(summ<<1)+ch-48;
return summ*f;
}
#define int long long
int l[500],r[500],block,n,m,num,belong[100005],b[100005],a[100005],pos[100005];
void build()//预处理
{
if(n%block!=0)
{
num=block+1;
}
else num=block;
for(int i=1;i<=num;i++)
{
l[i]=(i-1)*block+1;
r[i]=i*block;
}
r[num]=n;
for(int i=1;i<=num;i++)
sort(b+l[i],b+r[i]+1);
for(int i=1;i<=n;i++)
{
belong[i]=(i-1)/block+1;
}
}
void ybh(int x,int c)//单点修改,暴力即可
{
a[x]=c;
for(int i=l[belong[x]];i<=r[belong[x]];i++)
b[i]=a[i];
sort(b+l[belong[x]],b+r[belong[x]]+1);
}
int getnum(int x,int v)//块内二分
{
int ln=l[x],rn=r[x],mid;
while(ln<=rn)
{
mid=ln+rn>>1;
if(b[mid]<v) ln=mid+1;
else rn=mid-1;
}
return ln-l[x];
}
int pd(int x,int y,int v)//分块验证
{
int res=0;
if(belong[x]==belong[y])
{
for(int i=x;i<=y;i++)
{
if(a[i]<v)
res++;
}
return res;
}
for(int i=x;i<=r[belong[x]];i++)
{
if(a[i]<v) res++;
}
for(int i=l[belong[y]];i<=y;i++)
{
if(a[i]<v) res++;
}
for(int i=belong[x]+1;i<belong[y];i++)
res+=(getnum(i,v));//分块区间再2分
return res;
}
int qu(int x,int y,int k)//二分就第k小
{
int res=0,l=0,r=1e9,mid;
while(l<=r)
{
mid=l+r>>1;
cout<<pd(x,y,mid)<<endl;
if(pd(x,y,mid)<k)
l=mid+1;
else
{
r=mid-1;
res=mid;
}
}
return res-1;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
a[i]=getint();
b[i]=a[i];
}
block=sqrt(n);
build();
for(int i=1;i<=m;i++)
{
char s;
int lx,ly,kk;
cin>>s;
if(s=='Q')
{
lx=getint();
ly=getint();
kk=getint();
cout<<qu(lx,ly,kk)<<endl;
}
else {
scanf("%lld%lld",&lx,&kk);
ybh(lx,kk);
}
}
return 0;
}