您的位置:首页 > 其它

[bzoj3065] 带插入区间K小值

2016-04-07 14:15 344 查看
  腾爷手把手带你卡OJ系列。

  靠谱些的做法应该是替罪羊树套权值线段树= =

  然而某奇怪论文表示强行块状链表并不会被卡..而且还能进第一页233。

  所以就跟着腾爷学块链了= =

  感觉块链就是一本正经的暴力。。。分块后,块与块之间是用链表的姿势联系在一起的。

  插入的话强行插进那个块里,如果当前块的太大的话,就分成两块。。

  其他东西和分块一样。

  每个块里面记录原数列和排序后的,每次查找第k大的时候二分答案,对于每个二分出的答案mid,在每个块里面二分。。。

  单次查询复杂度O(n/B*log²n)....这种复杂度能够艹翻各种树套树简直是。。。

  其实如果对于每个块建一颗权值线段树的话,可以少掉一个log。。但实测线段树的常数比一个log的影响还大233

  至于块大小的正确选择。。先把总的复杂度算出来。然后利用奇怪的函数图像绘制工具就可以搞出来啦

  块的大小在750左右比较科学= =。。。

  腾爷轻松进前10%%%。。。我改半天越跑越慢>_<最后只挤进了第二页

  这个故事告诉我们千万不要怀疑分块的速度&&千万不要试图和神犇比常数

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int kuai=423;
int mp[233][888],pre[233][888],sz[233],aft[233];
int tmp[2333];
int i,j,k,n,m,num,mn,mx,lastans;

int ra;char rx;
inline int read(){
rx=getchar(),ra=0;
while(rx<'0'||rx>'9')rx=getchar();
while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
}

inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}
inline void swap(int &a,int &b){int c=a;a=b,b=c;}
inline int getk(int x,int y,int k){
int l=mn,r=mx,mid,mnnum,i,l1,r1,mid1;
short lpos,rpos;
for(lpos=1;sz[lpos]<x;lpos=aft[lpos])x-=sz[lpos];
for(rpos=1;sz[rpos]<y;rpos=aft[rpos])y-=sz[rpos];
if(lpos!=rpos){
for(i=1,tmp[0]=0;i<=y;i++)tmp[++tmp[0]]=pre[rpos][i];
for(i=x;i<=sz[lpos];i++)tmp[++tmp[0]]=pre[lpos][i];
sort(tmp+1,tmp+1+tmp[0]);
}
while(l<r){
mid=l+r+1>>1,mnnum=0;
if(lpos==rpos){
for(i=x;i<=y;i++)if(pre[lpos][i]<mid)mnnum++;
}else{
for(l1=0,r1=tmp[0];l1<r1;)
if(tmp[(mid1=l1+r1+1>>1)]<mid)l1=mid1;else r1=mid1-1;
mnnum=l1;
for(i=aft[lpos];i!=rpos&&mnnum<k;mnnum+=l1,i=aft[i])
for(l1=0,r1=sz[i];l1<r1;)
if(mp[i][(mid1=l1+r1+1>>1)]<mid)l1=mid1;else r1=mid1-1;
}
if(mnnum<k)l=mid;else r=mid-1;
}
return l;
}
inline void change(int x,int v){
register int i,j;
mn=min(mn,v),mx=max(mx,v);
for(i=1;sz[i]<x;i=aft[i])x-=sz[i];
if(pre[i][x]==v)return;
for(j=1;j<=sz[i]&&mp[i][j]<pre[i][x];j++);
mp[i][j]=pre[i][x]=v;
while(j>1&&mp[i][j-1]>mp[i][j])swap(mp[i][j],mp[i][j-1]),j--;
while(j<sz[i]&&mp[i][j+1]<mp[i][j])swap(mp[i][j],mp[i][j+1]),j++;
}

inline void split(int x){
aft[++num]=aft[x],aft[x]=num,sz[num]=sz[x]>>1,sz[x]-=sz[num],
memcpy(pre[num]+1,pre[x]+1+sz[x],sz[num]<<2),memcpy(mp[num],pre[num],(sz[num]+1)<<2),
sort(mp[num]+1,mp[num]+1+sz[num]),
memcpy(mp[x],pre[x],(sz[x]+1)<<2),sort(mp[x]+1,mp[x]+1+sz[x]);
}
inline void insert(int x,int v){
int i,j;
mn=min(mn,v),mx=max(mx,v);
for(i=1;sz[i]+1<x;i=aft[i])x-=sz[i];
//pre[i][++sz[i]]=v;
sz[i]++;
for(j=sz[i];j>x;j--)pre[i][j]=pre[i][j-1];
pre[i][x]=v;
if(sz[i]>=kuai*2)split(i);else
for(mp[i][sz[i]]=v,j=sz[i];j>1&&mp[i][j-1]>mp[i][j];)swap(mp[i][j],mp[i][j-1]),j--;

}
int main(){
n=read();mn=70023,mx=0;
num=(n+kuai-1)/kuai;int now=1;
for(i=1;i<=n;i++)
now+=sz[now]==kuai,sz[now]++,
mp[now][sz[now]]=pre[now][sz[now]]=read();
for(i=1;i<=num;i++)sort(mp[i]+1,mp[i]+1+sz[i]);
for(i=1;i<num;i++)aft[i]=i+1;
for(i=2,mn=mp[1][1],mx=mp[1][sz[1]];i<=num;i++)
mn=min(mn,mp[i][1]),mx=max(mx,mp[i][sz[i]]);

//  printf("  %d %d\n",mn,mx);

int x,y,z;char id;
for(int m=read();m;m--){
for(id=getchar();id<'A'||id>'Z';id=getchar());
x=read()^lastans,y=read()^lastans;
if(id=='Q')z=read()^lastans,lastans=getk(x,y,z),
//                  printf("       %d--%d %d\n",x,y,z),
printf("%d\n",lastans);else
if(id=='I')insert(x,y);else
change(x,y);
//      for(i=1;i;printf("  "),i=aft[i])for(j=1;j<=sz[i];j++)printf(" %d",pre[i][j]);puts("");
//      for(i=1;i;printf("  "),i=aft[i])for(j=1;j<=sz[i];j++)printf(" %d",mp[i][j]);puts("");
}
return 0;
}


View Code
  PS:腾爷喜闻乐见地把原来论文里的程序挤出了第一页2333
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: