也是很久以前奇葩做法搞的题,补个解题报告。
大爷的做法:听说是把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>
//Read
char * 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);
}
}
总结:
很久以前写的题。。现在并不知道该总结什么了。。感觉总是弄些巨难写代码巨长常数巨大的分块真是傻逼。