[bzoj3065]带插入区间K小值 解题报告
来源:互联网 发布:浙江严查环保数据作假 编辑:程序博客网 时间:2024/05/03 08:46
傻逼怎么做:
先用一个块链维护序列,做到
再用一个块链维护权值,每个块维护按位置排序的序列。查询的时候从小到大枚举每个块,先在块里二分统计块内在查询区间中的个数,然后如果发现答案在这个块里,就直接暴力找到第k小的是哪个。取块大小等于
总的时间复杂度就是
鸟哥的做法:
用块链维护,每个块维护每种权值出现次数的前缀和、和对一块权值出现次数的前缀和。这样时间复杂度就是
我的代码:
#include<cstdio>#include<iostream>using namespace std;#include<algorithm>#include<cassert>#include<cstring>#include<cmath>const int N=7e4+5,A=7e4+5,Q=175000+5;int n;char * cp=(char *)malloc(30000000);void in(int &x){ bool flag=0; while(*cp<'0'||*cp>'9')flag=*cp++=='-'; for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0'); if(flag)x=-x;}char * os=(char *)malloc(500000),* op=os;void out(int x){ if(x){ out(x/10); *op++='0'+x%10; }}int w[N];int p_pos1[N],p_pos2[N];int w_pos1[N],w_pos2[N];//只有插入 const int S=200;//const int S=200;//S∈[200,300]//N/S∈[233,350]int ptot=1;int p_block[1000+5][1000+5];int p_num[1000+5],p_pos0[1000+5];void p_out(){ printf("-----out p:\n"); for(int i=1;i<ptot;++i){ printf("%d:",p_num[i]); for(int j=1;j<=p_block[p_num[i]][0];++j)printf("%d(%d,%d) ",p_block[p_num[i]][j],p_pos1[p_block[p_num[i]][j]],p_pos2[p_block[p_num[i]][j]]); puts(""); }}void p_build(){ for(int i=1;i<=n;++i){ if(p_block[ptot][0]==S)++ptot; ++p_block[ptot][0]; p_block[ptot][p_block[ptot][0]]=i; p_pos1[i]=ptot,p_pos2[i]=p_block[ptot][0]; } for(int i=ptot++;i;--i)p_num[i]=p_pos0[i]=i;}void p_insert(int x){ int i=1,j; for(;x-p_block[p_num[i]][0]>0&&i+1<ptot;++i)x-=p_block[p_num[i]][0]; int bi=p_num[i]; for(j=++p_block[bi][0];j>x;--j){ p_block[bi][j]=p_block[bi][j-1]; p_pos2[p_block[bi][j]]=j; } p_block[bi][x]=n; p_pos1[n]=bi,p_pos2[n]=x; if(p_block[bi][0]==S<<1){ p_block[bi][0]=S; memcpy(p_block[ptot]+1,p_block[bi]+S+1,sizeof(int)*S); p_block[ptot][0]=S; for(j=S;j;--j){ p_pos1[p_block[ptot][j]]=ptot; p_pos2[p_block[ptot][j]]=j; } x=i; for(i=ptot-1;i>x;--i){ p_num[i+1]=p_num[i]; p_pos0[p_num[i]]=i+1; } p_num[x+1]=ptot; p_pos0[ptot]=x+1; ++ptot; }}bool p_cmp(const int &a,const int &b){ return p_pos1[a]!=p_pos1[b]?p_pos0[p_pos1[a]]<p_pos0[p_pos1[b]]:p_pos2[a]<p_pos2[b];}//需要支持插入/删除 const int B=500;//const int B=1050;//B∈[500,2000]//N/B∈[35,140]struct WS{ int num,w; bool operator < (const WS & o)const{ return w<o.w; }}w_tmp[35000+5];int w_q[2000+5],w_h,w_t;int w_block[2000+5][2000+5],w_sorted[2000+5][2000+5];int w_last[2000+5],w_next[2000+5],w_first;void w_out(){ printf("---out w\n"); for(int i=w_first;i;i=w_next[i]){ printf("w_block[%d]\n",i); printf("sorted by w:"); for(int j=1;j<=w_block[i][0];++j)printf("%d ",w_block[i][j]); puts(""); printf("sorted by p:"); for(int j=1;j<=w_block[i][0];++j)printf("%d ",w_sorted[i][j]); puts(""); } //for(int i=1;i<n;++i)printf("pos[%d]={%d,%d}\n",i,w_pos1[i],w_pos2[i]);}void w_build(){ for(int i=1;i<=400;++i)w_q[i-1]=i; for(int i=1;i<=n;++i)w_tmp[i]=(WS){i,w[i]}; sort(w_tmp+1,w_tmp+n+1); for(int i=1;i<=n;++i){ if(w_block[w_q[w_h]][0]==B)++w_h; w_block[w_q[w_h]][++w_block[w_q[w_h]][0]]=w_tmp[i].num; w_pos1[w_tmp[i].num]=w_q[w_h],w_pos2[w_tmp[i].num]=w_block[w_q[w_h]][0]; } w_first=1; for(int i=++w_h;i>1;--i){ w_last[i]=i-1; w_next[i-1]=i; } for(int i=w_h;i;--i){ memcpy(w_sorted[i]+1,w_block[i]+1,sizeof(int)*w_block[i][0]); sort(w_sorted[i]+1,w_sorted[i]+w_block[i][0]+1,p_cmp); }}void w_split(int i){ if(w_block[i][0]>=B<<1){ int j; w_block[w_q[w_h]][0]=w_block[i][0]-(w_block[i][0]>>1); memcpy(w_block[w_q[w_h]]+1,w_block[i]+1+(w_block[i][0]>>1),sizeof(int)*w_block[w_q[w_h]][0]); for(j=w_block[w_q[w_h]][0];j;--j){ w_pos1[w_block[w_q[w_h]][j]]=w_q[w_h]; w_pos2[w_block[w_q[w_h]][j]]=j; } w_sorted[w_q[w_h]][0]=w_sorted[i][0]=0; int tmp; for(j=1;j<=w_block[i][0];++j){ tmp=w_pos1[w_sorted[i][j]]; w_sorted[tmp][++w_sorted[tmp][0]]=w_sorted[i][j]; } w_block[i][0]>>=1; w_next[w_q[w_h]]=w_next[i]; w_last[w_q[w_h]]=i; w_last[w_next[i]]=w_q[w_h]; w_next[i]=w_q[w_h]; w_h=(w_h+1)%400; }}int tmp[2000+5];void w_delete(int x){ int i=w_pos1[x],j; for(j=w_pos2[x];j<w_block[i][0];++j){ w_block[i][j]=w_block[i][j+1]; w_pos2[w_block[i][j]]=j; } j=w_block[i][0]; while(w_sorted[i][j]!=x)--j; for(;j<w_block[i][0];++j)w_sorted[i][j]=w_sorted[i][j+1]; --w_block[i][0]; if(w_block[i][0]){ if(w_block[i][0]<B&&w_next[i]){ memcpy(w_block[i]+w_block[i][0]+1,w_block[w_next[i]]+1,sizeof(int)*w_block[w_next[i]][0]); memcpy(w_block[w_next[i]]+1,w_block[i]+1,sizeof(int)*(w_block[i][0]+w_block[w_next[i]][0])); for(j=w_block[i][0];j;--j)w_pos1[w_block[i][j]]=w_next[i]; for(j=w_block[w_next[i]][0]+w_block[i][0];j>w_block[i][0];--j)w_pos2[w_block[w_next[i]][j]]=j; int k=1,o=1; for(j=1;j<=w_block[i][0]&&k<=w_block[w_next[i]][0];) if(p_cmp(w_sorted[i][j],w_sorted[w_next[i]][k])){ tmp[o++]=w_sorted[i][j++]; } else{ tmp[o++]=w_sorted[w_next[i]][k++]; } memcpy(tmp+o,w_sorted[i]+j,sizeof(int)*(w_block[i][0]-j+1)); memcpy(tmp+o,w_sorted[w_next[i]]+k,sizeof(int)*(w_block[w_next[i]][0]-k+1)); w_block[w_next[i]][0]+=w_block[i][0]; memcpy(w_sorted[w_next[i]]+1,tmp+1,sizeof(int)*w_block[w_next[i]][0]); w_next[w_last[i]]=w_next[i]; w_last[w_next[i]]=w_last[i]; if(i==w_first)w_first=w_next[i]; w_q[w_t]=i; w_t=(w_t+1)%400; w_split(w_next[i]); } } else{ w_next[w_last[i]]=w_next[i]; w_last[w_next[i]]=w_last[i]; if(i==w_first)w_first=w_next[i]; w_q[w_t]=i; w_t=(w_t+1)%400; }}void w_insert(int x){ int i=w_first,j; if(i==0){ i=w_first=w_q[w_h]; w_h=(w_h+1)%400; w_last[i]=w_next[i]=0; w_block[i][0]=1,w_block[i][1]=x; w_sorted[i][1]=x; w_pos1[x]=i,w_pos2[x]=1; } else{ while(w_next[i]&&w[w_block[w_next[i]][1]]<w[x])i=w_next[i]; for(j=++w_block[i][0];j>1&&w[w_block[i][j-1]]>=w[x];--j){ w_block[i][j]=w_block[i][j-1]; w_pos2[w_block[i][j]]=j; } w_block[i][j]=x; w_pos1[x]=i,w_pos2[x]=j; for(j=w_block[i][0];j>1&&p_cmp(x,w_sorted[i][j-1]);--j)w_sorted[i][j]=w_sorted[i][j-1]; w_sorted[i][j]=x; w_split(i); }}int main(){ freopen("bzoj_3065.in","r",stdin); freopen("bzoj_3065.out","w",stdout); fread(cp,1,30000000,stdin); int m; in(n); for(int i=1;i<=n;++i)in(w[i]); p_build(); w_build(); ++n; //p_out(),w_out(); int q; in(q); int x,y,k,val; int i,j; int lastans=0; int cnt; while(q--){ while(*cp<'A'||*cp>'Z')++cp; //printf("-------------\n"); switch(*cp++){ case 'Q': in(x),in(y),in(k); //x^=lastans,y^=lastans,k^=lastans; for(i=1;x>p_block[p_num[i]][0];++i){ x-=p_block[p_num[i]][0]; y-=p_block[p_num[i]][0]; } x=p_block[p_num[i]][x]; for(;y>p_block[p_num[i]][0];++i)y-=p_block[p_num[i]][0]; y=p_block[p_num[i]][y]; //printf("Get range:[%d,%d]\n",x,y); for(i=w_first;;i=w_next[i]){ cnt=upper_bound(w_sorted[i]+1,w_sorted[i]+w_block[i][0]+1,y,p_cmp)-lower_bound(w_sorted[i]+1,w_sorted[i]+w_block[i][0]+1,x,p_cmp); //printf("cnt(%d)=%d-%d\n",i,upper_bound(w_sorted[i]+1,w_sorted[i]+w_block[i][0]+1,y,p_cmp)-w_sorted[i],lower_bound(w_sorted[i]+1,w_sorted[i]+w_block[i][0]+1,x,p_cmp)-w_sorted[i]); if(k>cnt)k-=cnt; else{ for(j=1;j<=w_block[i][0];++j) if(!p_cmp(w_block[i][j],x)&&!p_cmp(y,w_block[i][j])&&--k==0){ lastans=w[w_block[i][j]]; break; } break; } } if(lastans)out(lastans); else *op++='0'; *op++='\n'; //printf("%d\n",lastans); break; case 'M': in(x),in(val); //x^=lastans,val^=lastans; for(i=1;x>p_block[p_num[i]][0];++i)x-=p_block[p_num[i]][0]; x=p_block[p_num[i]][x]; w_delete(x); w[x]=val; w_insert(x); break; case 'I': in(x),in(val); //x^=lastans,val^=lastans; w[n]=val; p_insert(x); w_insert(n); ++n; break; } //p_out(),w_out(); } fwrite(os,1,op-os,stdout);}
总结:
①一定要生成极限数据测试!
②注意发掘题目的性质——既然权值是静态的,而位置是动态的,那么我们为什么要用块链维护权值呢?
③块链其实可以在每个块维护
0 0
- [bzoj3065]带插入区间K小值 解题报告
- BZOJ3065 带插入区间K小值
- [bzoj3065]带插入区间K小值
- bzoj3065带插入区间K小值
- BZOJ3065 带插入区间K小值
- bzoj3065: 带插入区间K小值
- 【BZOJ3065】带插入区间K小值
- BZOJ3065: 带插入区间K小值(替罪羊树+权值线段树)
- 替罪羊树套线段树 【bzoj3065】 带插入区间k小值
- [bzoj3065]带插入区间K小值 替罪羊树套值域线段树
- BZO3065 带插入区间K小值
- 3065: 带插入区间K小值
- bzoj 3065 带插入区间k小值
- 【 bzoj 3065 】 带插入区间K小值 - 树套树乱搞
- bzoj 3065 带插入区间K小值
- BZOJ 3065: 带插入区间K小值
- BZOJ 3065 带插入区间K小值
- BZOJ 3065 带插入区间K小值 替罪羊树套线段树
- Android优化应用启动速度
- 111. Minimum Depth of Binary Tree
- Win10下安装Oracle11g 不满足配置解决方法
- 设计模式 学习 1:
- LeetCode102 Binary Tree Level Order Traversal Java
- [bzoj3065]带插入区间K小值 解题报告
- 设计模式 学习 2:
- Android Studio 的安装与第一个程序
- HDU 1197 Specialized Four-Digit Numbers(进制转换+暴力)
- C++第4次作业
- itext , drawString ,中文
- 有关思考的思考
- 《肖申克的救赎》影评
- 36. Valid Sudoku