[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
",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
",x,y,z),
 97                     printf("%d
",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 }
View Code

  PS:腾爷喜闻乐见地把原来论文里的程序挤出了第一页2333

原文地址:https://www.cnblogs.com/czllgzmzl/p/5363366.html