[bzoj3065] 带插入区间K小值
腾爷手把手带你卡OJ系列。
靠谱些的做法应该是替罪羊树套权值线段树= =
然而某奇怪论文表示强行块状链表并不会被卡..而且还能进第一页233。
所以就跟着腾爷学块链了= =
感觉块链就是一本正经的暴力。。。分块后,块与块之间是用链表的姿势联系在一起的。
插入的话强行插进那个块里,如果当前块的太大的话,就分成两块。。
其他东西和分块一样。
每个块里面记录原数列和排序后的,每次查找第k大的时候二分答案,对于每个二分出的答案mid,在每个块里面二分。。。
单次查询复杂度O(n/B*log²n)....这种复杂度能够艹翻各种树套树简直是。。。
其实如果对于每个块建一颗权值线段树的话,可以少掉一个log。。但实测线段树的常数比一个log的影响还大233
至于块大小的正确选择。。先把总的复杂度算出来。然后利用奇怪的函数图像绘制工具就可以搞出来啦
块的大小在750左右比较科学= =。。。
腾爷轻松进前10%%%。。。我改半天越跑越慢>_<最后只挤进了第二页
这个故事告诉我们千万不要怀疑分块的速度&&千万不要试图和神犇比常数
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdlib> 6 #include<algorithm> 7 using namespace std; 8 const int kuai=423; 9 int mp[233][888],pre[233][888],sz[233],aft[233]; 10 int tmp[2333]; 11 int i,j,k,n,m,num,mn,mx,lastans; 12 13 int ra;char rx; 14 inline int read(){ 15 rx=getchar(),ra=0; 16 while(rx<'0'||rx>'9')rx=getchar(); 17 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 18 } 19 20 inline int min(int a,int b){return a<b?a:b;} 21 inline int max(int a,int b){return a>b?a:b;} 22 inline void swap(int &a,int &b){int c=a;a=b,b=c;} 23 inline int getk(int x,int y,int k){ 24 int l=mn,r=mx,mid,mnnum,i,l1,r1,mid1; 25 short lpos,rpos; 26 for(lpos=1;sz[lpos]<x;lpos=aft[lpos])x-=sz[lpos]; 27 for(rpos=1;sz[rpos]<y;rpos=aft[rpos])y-=sz[rpos]; 28 if(lpos!=rpos){ 29 for(i=1,tmp[0]=0;i<=y;i++)tmp[++tmp[0]]=pre[rpos][i]; 30 for(i=x;i<=sz[lpos];i++)tmp[++tmp[0]]=pre[lpos][i]; 31 sort(tmp+1,tmp+1+tmp[0]); 32 } 33 while(l<r){ 34 mid=l+r+1>>1,mnnum=0; 35 if(lpos==rpos){ 36 for(i=x;i<=y;i++)if(pre[lpos][i]<mid)mnnum++; 37 }else{ 38 for(l1=0,r1=tmp[0];l1<r1;) 39 if(tmp[(mid1=l1+r1+1>>1)]<mid)l1=mid1;else r1=mid1-1; 40 mnnum=l1; 41 for(i=aft[lpos];i!=rpos&&mnnum<k;mnnum+=l1,i=aft[i]) 42 for(l1=0,r1=sz[i];l1<r1;) 43 if(mp[i][(mid1=l1+r1+1>>1)]<mid)l1=mid1;else r1=mid1-1; 44 } 45 if(mnnum<k)l=mid;else r=mid-1; 46 } 47 return l; 48 } 49 inline void change(int x,int v){ 50 register int i,j; 51 mn=min(mn,v),mx=max(mx,v); 52 for(i=1;sz[i]<x;i=aft[i])x-=sz[i]; 53 if(pre[i][x]==v)return; 54 for(j=1;j<=sz[i]&&mp[i][j]<pre[i][x];j++); 55 mp[i][j]=pre[i][x]=v; 56 while(j>1&&mp[i][j-1]>mp[i][j])swap(mp[i][j],mp[i][j-1]),j--; 57 while(j<sz[i]&&mp[i][j+1]<mp[i][j])swap(mp[i][j],mp[i][j+1]),j++; 58 } 59 60 inline void split(int x){ 61 aft[++num]=aft[x],aft[x]=num,sz[num]=sz[x]>>1,sz[x]-=sz[num], 62 memcpy(pre[num]+1,pre[x]+1+sz[x],sz[num]<<2),memcpy(mp[num],pre[num],(sz[num]+1)<<2), 63 sort(mp[num]+1,mp[num]+1+sz[num]), 64 memcpy(mp[x],pre[x],(sz[x]+1)<<2),sort(mp[x]+1,mp[x]+1+sz[x]); 65 } 66 inline void insert(int x,int v){ 67 int i,j; 68 mn=min(mn,v),mx=max(mx,v); 69 for(i=1;sz[i]+1<x;i=aft[i])x-=sz[i]; 70 //pre[i][++sz[i]]=v; 71 sz[i]++; 72 for(j=sz[i];j>x;j--)pre[i][j]=pre[i][j-1]; 73 pre[i][x]=v; 74 if(sz[i]>=kuai*2)split(i);else 75 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--; 76 77 } 78 int main(){ 79 n=read();mn=70023,mx=0; 80 num=(n+kuai-1)/kuai;int now=1; 81 for(i=1;i<=n;i++) 82 now+=sz[now]==kuai,sz[now]++, 83 mp[now][sz[now]]=pre[now][sz[now]]=read(); 84 for(i=1;i<=num;i++)sort(mp[i]+1,mp[i]+1+sz[i]); 85 for(i=1;i<num;i++)aft[i]=i+1; 86 for(i=2,mn=mp[1][1],mx=mp[1][sz[1]];i<=num;i++) 87 mn=min(mn,mp[i][1]),mx=max(mx,mp[i][sz[i]]); 88 89 // printf(" %d %d\n",mn,mx); 90 91 int x,y,z;char id; 92 for(int m=read();m;m--){ 93 for(id=getchar();id<'A'||id>'Z';id=getchar()); 94 x=read()^lastans,y=read()^lastans; 95 if(id=='Q')z=read()^lastans,lastans=getk(x,y,z), 96 // printf(" %d--%d %d\n",x,y,z), 97 printf("%d\n",lastans);else 98 if(id=='I')insert(x,y);else 99 change(x,y); 100 // for(i=1;i;printf(" "),i=aft[i])for(j=1;j<=sz[i];j++)printf(" %d",pre[i][j]);puts(""); 101 // for(i=1;i;printf(" "),i=aft[i])for(j=1;j<=sz[i];j++)printf(" %d",mp[i][j]);puts(""); 102 } 103 return 0; 104 }
PS:腾爷喜闻乐见地把原来论文里的程序挤出了第一页2333