首页 > 代码库 > 【分块】bzoj1901 Zju2112 Dynamic Rankings

【分块】bzoj1901 Zju2112 Dynamic Rankings

区间k大,分块大法好,每个区间内存储一个有序表。

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

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

 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 int n,a[10001],num[10001],qx,qy,k,p,v,m,sz,sum,l[101],r[101],b[10001],tmp[1001]; 7 char s[2]; 8 void makeblock() 9 {10     memcpy(b,a,sizeof(a));11     sz=sqrt((double)n*log2(n));12     for(sum=1;sum*sz<n;sum++)13       {14         l[sum]=(sum-1)*sz+1;15         r[sum]=sum*sz;16         for(int i=l[sum];i<=r[sum];i++)17           num[i]=sum;18         sort(b+l[sum],b+r[sum]+1);19       }20     l[sum]=sz*(sum-1)+1;21     r[sum]=n;22     sort(b+l[sum],b+r[sum]+1);23     for(int i=l[sum];i<=r[sum];i++)24       num[i]=sum;25 }26 void query(int L,int R,int k)27 {28     if(num[L]+1>=num[R])29       {30         int en=0;31         for(int i=L;i<=R;i++) tmp[++en]=a[i];32         sort(tmp+1,tmp+en+1);33         printf("%d\n",tmp[k]);34       }35     else36       {37         int x=0,y=1000000001;38         while(x!=y)39           {40             int mid=x+y>>1,cnt=0;41             for(int i=L;i<=r[num[L]];i++) if(a[i]<mid) cnt++;42             for(int i=l[num[R]];i<=R;i++) if(a[i]<mid) cnt++; //统计<mid的值数43             for(int i=num[L]+1;i<num[R];i++) cnt+=( lower_bound(b+l[i],b+r[i]+1,mid) - (b+l[i]) );44             if(cnt>=k) y=mid;45             else x=mid+1;46           }47         printf("%d\n",x-1);48       }49 }50 void update(int p,int v)51 {52     *lower_bound(b+l[num[p]],b+r[num[p]]+1,a[p])=v;53     sort(b+l[num[p]],b+r[num[p]]+1);54     a[p]=v;55 }56 int main()57 {58     scanf("%d%d",&n,&m);59     for(int i=1;i<=n;i++) scanf("%d",&a[i]);60     makeblock();61     for(int i=1;i<=m;i++)62       {63         scanf("%s",s);64         if(s[0]==Q) {scanf("%d%d%d",&qx,&qy,&k);query(qx,qy,k);}65         else {scanf("%d%d",&p,&v);update(p,v);}66       }67     return 0;68 }

 

【分块】bzoj1901 Zju2112 Dynamic Rankings