您的位置:首页 > 其它

【分块】bzoj1901 Zju2112 Dynamic Rankings

2014-09-29 07:15 330 查看
区间k大,分块大法好,每个区间内存储一个有序表。

二分答案,统计在区间内小于二分到的答案的值的个数,在每个整块内二分、零散的暴力即可。

还是说∵有二分操作,∴每个块的大小定为sqrt(n*log2(n))比较快呢。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,a[10001],num[10001],qx,qy,k,p,v,m,sz,sum,l[101],r[101],b[10001],tmp[1001];
char s[2];
void makeblock()
{
memcpy(b,a,sizeof(a));
sz=sqrt((double)n*log2(n));
for(sum=1;sum*sz<n;sum++)
{
l[sum]=(sum-1)*sz+1;
r[sum]=sum*sz;
for(int i=l[sum];i<=r[sum];i++)
num[i]=sum;
sort(b+l[sum],b+r[sum]+1);
}
l[sum]=sz*(sum-1)+1;
r[sum]=n;
sort(b+l[sum],b+r[sum]+1);
for(int i=l[sum];i<=r[sum];i++)
num[i]=sum;
}
void query(int L,int R,int k)
{
if(num[L]+1>=num[R])
{
int en=0;
for(int i=L;i<=R;i++) tmp[++en]=a[i];
sort(tmp+1,tmp+en+1);
printf("%d\n",tmp[k]);
}
else
{
int x=0,y=1000000001;
while(x!=y)
{
int mid=x+y>>1,cnt=0;
for(int i=L;i<=r[num[L]];i++) if(a[i]<mid) cnt++;
for(int i=l[num[R]];i<=R;i++) if(a[i]<mid) cnt++; //统计<mid的值数
for(int i=num[L]+1;i<num[R];i++) cnt+=( lower_bound(b+l[i],b+r[i]+1,mid) - (b+l[i]) );
if(cnt>=k) y=mid;
else x=mid+1;
}
printf("%d\n",x-1);
}
}
void update(int p,int v)
{
*lower_bound(b+l[num[p]],b+r[num[p]]+1,a[p])=v;
sort(b+l[num[p]],b+r[num[p]]+1);
a[p]=v;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
makeblock();
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='Q') {scanf("%d%d%d",&qx,&qy,&k);query(qx,qy,k);}
else {scanf("%d%d",&p,&v);update(p,v);}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: