Description
对于一个n×n(n≤5×105)的矩阵进行m(m≤2×105)次操作:
1. 将格子(x,y)里的数字加上A(A>0);
2. 求矩形(x1,y1)−(x2,y2)中的数字和。
强制在线,空间限制20MB。
Solution
k-d树。
对于操作1,将(x,y)插入树中,当树的大小达到一定程度就重建整棵树。
对于操作2,做法类似于线段树,如果查询矩形完全包含目前子树所表示的矩形,就返回这个子树内的和;否则就递归的向左右子树内查询。
并不知道k-d树的时间复杂度如何算。
Code
这个代码目前TLE!明天问问Icefox大佬
噫!我过了
//简单题
#include <cstdio>
#include <algorithm>
using namespace std;
int pre;
inline char gc()
{
static char now[1<<16],*S,*T;
if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
return *S++;
}
inline int read()
{
int x=0; char ch=gc();
while(ch<'0'||'9'<ch) ch=gc();
while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
return x^pre;
}
int const N=2e5+10;
int const INF=0x7FFFFFFF;
int n;
#define chL ch[p][0]
#define chR ch[p][1]
int D,ndCnt,rt,ch[N][2],sum[N];
struct point
{
int c[2],v;
point(int x=0,int y=0,int v0=0){c[0]=x,c[1]=y,v=v0;}
}pt[N];
struct zone
{
int c1[2],c2[2];
zone(int x1=0,int y1=0,int x2=0,int y2=0)
{
c1[0]=x1,c1[1]=y1;
c2[0]=x2,c2[1]=y2;
}
}zn[N];
bool cmpPt(point x,point y) {return x.c[D]<y.c[D];}
void create(int p,point A)
{
pt[p]=A;
for(int k=0;k<2;k++) zn[p].c1[k]=zn[p].c2[k]=A.c[k];
chL=chR=0; sum[p]=A.v;
}
void update(int p)
{
for(int k=0;k<2;k++)
{
zn[p].c1[k]=min(pt[p].c[k],min(zn[chL].c1[k],zn[chR].c1[k]));
zn[p].c2[k]=max(pt[p].c[k],max(zn[chL].c2[k],zn[chR].c2[k]));
}
sum[p]=pt[p].v+sum[chL]+sum[chR];
}
inline bool equal(point x,point y)
{
for(int k=0;k<2;k++) if(x.c[k]!=y.c[k]) return false;
return true;
}
void build(int &p,int L,int R,int k0)
{
int mid=L+R>>1; D=k0;
nth_element(pt+L,pt+mid,pt+R+1,cmpPt);
create(p=mid,pt[mid]);
if(L<mid) build(chL,L,mid-1,k0^1);
if(mid<R) build(chR,mid+1,R,k0^1);
update(p);
}
void ins(int &p,point A,int k0)
{
if(p==0) {create(p=++ndCnt,A); return;}
if(equal(A,pt[p])) {pt[p].v+=A.v,sum[p]+=A.v; return;}
ins(ch[p][A.c[k0]>pt[p].c[k0]],A,k0^1);
update(p);
}
inline bool in(zone z,zone z0)
{
for(int k=0;k<2;k++) if(z0.c1[k]<z.c1[k]||z.c2[k]<z0.c2[k]) return false;
return true;
}
inline bool in(zone z,point A)
{
for(int k=0;k<2;k++) if(A.c[k]<z.c1[k]||z.c2[k]<A.c[k]) return false;
return true;
}
inline bool out(zone z,zone z0)
{
for(int k=0;k<2;k++)
{
bool outL=z0.c1[k]<z.c1[k]&&z0.c2[k]<z.c1[k];
bool outR=z0.c1[k]>z.c2[k]&&z0.c2[k]>z.c2[k];
if(outL||outR) return true;
}
return false;
}
int query(int p,zone z)
{
if(in(z,zn[p])) return sum[p];
int res=0;
if(in(z,pt[p])) res+=pt[p].v;
if(!out(z,zn[chL])) res+=query(chL,z);
if(!out(z,zn[chR])) res+=query(chR,z);
return res;
}
int main()
{
pre=0; n=read();
for(int k=0;k<2;k++) zn[0].c1[k]=INF,zn[0].c2[k]=-INF;
while(true)
{
int opt=read()^pre;
if(opt==1)
{
int x=read(),y=read(),k=read();
ins(rt,point(x,y,k),0);
if(ndCnt%10000==0) rt=0,build(rt,1,ndCnt,0);
}
else if(opt==2)
{
int x1=read(),y1=read(),x2=read(),y2=read();
printf("%d\n",pre=query(rt,zone(x1,y1,x2,y2)));
}
else break;
}
return 0;
}
P.S.
到底什么锅啊!跟Icefox的代码对拍十组都一样啊!
建树/插入节点的时候,参数要单独传一个k0,表示当前这层以第k0维作为划分标准,而不能用全局变量。那个全局变量D只是用于做nth_element()
的…
对拍正确可能是因为只有两维+数据分散,有时候k0错了也能跳到正确的子树上