[bzoj4066]简单题 解题报告
来源:互联网 发布:杰奇cms破解版 编辑:程序博客网 时间:2024/05/22 13:46
也是很久以前奇葩做法搞的题,补个解题报告。
大爷的做法:听说是把k-d树写成替罪的或是每
傻逼的做法:
我们是理论计算机科学家(当时我弱不会k-d树。。),所以我们需要思考科学的做法。
分块!
考虑将横坐标分成
我们可以这样分块,我们按x从小到大扫描,如果
而查询一个矩形的时候,考虑它的一个边界x=a,如果它不完全覆盖的块的y长度大于1,那么显然这条边界上的所有块的总点数不会超过
于是我们就得到了时间复杂度
最后口胡一下更加科学的搞法!
最近做了带插入区间第k大,对块链基本有了一些了解。这题如果用块链搞的话可以像bzoj3720我的傻逼做法一样,对x和y分别维护一个块链,然后在x中维护y的每个块的前缀和。这样时间复杂度是
显然比上面那种做法会好写很多+快很多。。但是我懒得写了。。
然后非常喜闻乐见。。我写了9K,别人都只写了3、4K。。
#include<cstdio>#include<cstring>#include<iostream>using namespace std;#include<algorithm>//Readchar * cp=(char *)malloc(5672730);inline void in(int &x){ while(*cp<'0'||*cp>'9')++cp; x=0; while(*cp>='0'&&*cp<='9')x=x*10+(*cp++^'0');}struct PS{ int x,y,A;}point[200005];inline bool hcmp(const int & a,const int & b){ return point[a].x!=point[b].x?point[a].x<point[b].x:point[a].y<point[b].y;}inline bool scmp(const int & a,const int & b){ return point[a].y<point[b].y;}//块下链表,块的编号从1开始。 int heng[955],shu[955];int s[955][955];int ptr[955][955],next[200005],succ[200005];int ltot=1;//排序过的点,h代表以heng为第一关键字,s代表以shu为第一关键字。 int ah[200005],as[200005],bs[200005];//对付蛋疼的询问。 int x1,y1,x2,y2;inline int query(int bx,int by){ //cout<<"Query("<<bx<<","<<by<<")\n"; int ans=0; //cout<<ptr[3][2]<<endl; for(int i=ptr[bx][by];i;i=next[i]){ //cout<<succ[i]<<"("<<i<<"):"; if(x1<=point[succ[i]].x&&point[succ[i]].x<=x2&&y1<=point[succ[i]].y&&point[succ[i]].y<=y2){ ans+=point[succ[i]].A; //cout<<"Get!"; } //puts(""); } //cout<<"Ans="<<ans<<endl; return ans;}inline int cquery(int bx,int ly,int ry){ //cout<<"c("<<bx<<","<<"["<<ly<<","<<ry<<"])\n"; return ly!=ry?s[bx][ry-1]-s[bx][ly]+(y2==shu[ry]?s[bx][ry]-s[bx][ry-1]:query(bx,ry))+(y1==(ly>1?shu[ly-1]+1:1)?s[bx][ly]-s[bx][ly-1]:query(bx,ly)):(ly==(ly>1?shu[ly-1]+1:1)&&ry==shu[ry]?s[bx][ry]-s[bx][ly-1]:query(bx,ly));}inline int nquery(int bx,int ly,int ry){ int ans=0; while(ly<=ry)ans+=query(bx,ly++); return ans;}int main(){ fread(cp,1,5672730,stdin); int n,i,opt,bx,by,last_ans=0,j,lx,rx,ly,ry; int atot=0,btot=0;//a是有多少个科学的点,b是有多少个不科学的点。不科学的点在科学的点的后面。 int ptot=1;//p是有多少个点。 int tot;//归并排序用的。 int now=0; int S=400; in(n); heng[0]=1,heng[1]=n; shu[0]=1,shu[1]=n; for(in(opt);opt!=3;in(opt)) if(opt==1){ in(point[ptot].x),in(point[ptot].y),in(point[ptot].A); point[ptot].x^=last_ans,point[ptot].y^=last_ans,point[ptot].A^=last_ans; bx=lower_bound(heng+1,heng+heng[0]+1,point[ptot].x)-heng; by=lower_bound(shu+1,shu+shu[0]+1,point[ptot].y)-shu; ah[atot+btot]=as[atot+btot]=ptot; ++btot; //cout<<ltot<<":"<<bx<<","<<by<<"->"<<ptr[bx][by]<<endl; next[ltot]=ptr[bx][by],ptr[bx][by]=ltot,succ[ltot++]=ptot; for(;by<=shu[0];++by)s[bx][by]+=point[ptot].A; ++ptot; if(btot>S){ //puts("----Rebuild-----"); //先清空。 ltot=1; for(i=heng[0];i;--i){ memset(s[i],0,sizeof(int)*(shu[0]+1)); memset(ptr[i],0,sizeof(int)*(shu[0]+1)); } heng[0]=shu[0]=0; //归并 tot=0; sort(ah+atot,ah+atot+btot,hcmp); for(i=j=0;i<atot&&j<btot;)bs[tot++]=hcmp(ah[i],ah[atot+j])?ah[i++]:ah[atot+j++]; while(i<atot)bs[tot++]=ah[i++]; while(j<btot)bs[tot++]=ah[atot+j++]; memcpy(ah,bs,sizeof(int)*tot); tot=0; sort(as+atot,as+atot+btot,scmp); for(i=j=0;i<atot&&j<btot;)bs[tot++]=scmp(as[i],as[atot+j])?as[i++]:as[atot+j++]; while(i<atot)bs[tot++]=as[i++]; while(j<btot)bs[tot++]=as[atot+j++]; memcpy(as,bs,sizeof(int)*tot); atot+=btot; /*for(i=0;i<atot;++i)cout<<ah[i]<<" "; cout<<endl;*/ //重新建块 now=btot=0; shu[0]=1; for(i=0;i<atot;i=j+1){ j=i; while(point[as[j+1]].y==point[as[j]].y)++j; if(now&&now+j-i+1>S){ shu[shu[0]++]=point[as[i-1]].y; now=0; } if(j-i+1<S){ now+=j-i+1; j=i-1; do{ ++j; bs[as[j]]=shu[0]; }while(point[as[j]].y==point[as[j+1]].y); } else{ if(!shu[0]){ shu[1]=point[as[i]].y-1; shu[0]=2; } else{ if(point[as[i]].y!=1&&!(shu[0]>1&&shu[shu[0]-1]==point[as[i]].y-1))shu[shu[0]++]=point[as[i]].y-1; shu[shu[0]]=point[as[i]].y; j=i-1; do{ ++j; bs[as[j]]=shu[0]; }while(point[as[j]].y==point[as[j+1]].y); ++shu[0]; } now=0; } } if(shu[shu[0]-1]==n)--shu[0]; else shu[shu[0]]=n; now=0; heng[0]=1; for(i=0;i<atot;i=j+1){ //cout<<"---"<<i<<"---\n"; j=i; while(point[ah[j+1]].x==point[ah[j]].x)++j; if(now&&now+j-i+1>S){ heng[heng[0]++]=point[ah[i-1]].x; now=0; } if(j-i+1<S){ now+=j-i+1; j=i-1; do{ ++j; next[ltot]=ptr[heng[0]][bs[ah[j]]],ptr[heng[0]][bs[ah[j]]]=ltot,succ[ltot++]=ah[j]; s[heng[0]][bs[ah[j]]]+=point[ah[j]].A; //cout<<ah[j]<<":"<<heng[0]<<","<<bs[ah[j]]<<endl; }while(point[ah[j]].x==point[ah[j+1]].x); } else{ if(!heng[0]){ heng[1]=point[ah[i]].x-1; heng[0]=2; } else{ if(point[ah[i]].x!=1&&!(heng[0]>1&&heng[heng[0]-1]==point[ah[i]].x-1))heng[heng[0]++]=point[ah[i]].x-1; heng[heng[0]]=point[ah[i]].x; j=i-1; do{ ++j; next[ltot]=ptr[heng[0]][bs[ah[j]]],ptr[heng[0]][bs[ah[j]]]=ltot,succ[ltot++]=ah[j]; s[heng[0]][bs[ah[j]]]+=point[ah[j]].A; //cout<<ah[j]<<":"<<heng[0]<<","<<bs[ah[j]]<<endl; }while(point[ah[j]].x==point[ah[j+1]].x); ++heng[0]; } now=0; } } if(heng[heng[0]-1]==n)--heng[0]; else heng[heng[0]]=n; /*for(i=1;i<=shu[0];++i)cout<<" "<<shu[i]; cout<<endl; for(i=1;i<=heng[0];++i)cout<<" "<<heng[i]; cout<<endl;*/ for(i=heng[0];i;--i) for(j=1;j<=shu[0];++j){ //cout<<"S("<<i<<","<<j<<")="<<s[i][j]<<endl; s[i][j]+=s[i][j-1]; } } } else{ in(x1),in(y1),in(x2),in(y2); x1^=last_ans,y1^=last_ans,x2^=last_ans,y2^=last_ans; //cout<<"["<<x1<<","<<x2<<"]*("<<y1<<","<<y2<<"]\n"; lx=lower_bound(heng+1,heng+heng[0]+1,x1)-heng,rx=lower_bound(heng+1,heng+heng[0]+1,x2)-heng; ly=lower_bound(shu+1,shu+shu[0]+1,y1)-shu,ry=lower_bound(shu+1,shu+shu[0]+1,y2)-shu; last_ans=0; if(x2>=heng[lx]&&x1==(lx>1?heng[lx-1]:0)+1)last_ans+=cquery(lx,ly,ry); else last_ans+=nquery(lx,ly,ry); for(i=lx;++i<rx;)last_ans+=cquery(i,ly,ry); if(rx!=lx) if(x2==heng[rx])last_ans+=cquery(rx,ly,ry); else last_ans+=nquery(rx,ly,ry); printf("%d\n",last_ans); }}
总结:
很久以前写的题。。现在并不知道该总结什么了。。感觉总是弄些巨难写代码巨长常数巨大的分块真是傻逼。
- [bzoj4066]简单题 解题报告
- [bzoj4066]简单题
- 【BZOJ4066】简单题
- bzoj4066: 简单题
- BZOJ4066 简单题
- BZOJ4066: 简单题
- bzoj4066 简单题
- BZOJ4066: 简单题
- 【bzoj4066】简单题
- [BZOJ2683]=[BZOJ4066]简单题
- 【bzoj4066】【简单题】【kd树】
- [BZOJ4066]简单题(kd-tree)
- bzoj4066&2683简单题 K-Dtree
- [BZOJ4066]简单题(KD-tree)
- 【简单题】POJ1032解题报告
- bzoj 3687 简单题 bitset 解题报告
- 简单字符串排序解题报告
- BZOJ3687 简单题 解题报告 【递推】【bitset】
- mybatis异常:org.apache.ibatis.binding.BindingException: Parameter 'param' not found. Available param
- Mybatis设置打印sql语句
- Linux命令行显示指定行号的内容
- Eigen使用方法
- 【Android网络开发】(一)HTTP请求报文和HTTP响应报文
- [bzoj4066]简单题 解题报告
- ios面试题
- 神经网络反向传导算法
- SwipeToLoadLayout使用所要注意的一些细节
- Android Studio的使用总结
- xcode中混用arc和非arc模式
- leetcode——332——Reconstruct Itinerary
- android多分辨率适配
- C/C++复习:不等长字符串的排序(1)