洛谷4148 & BZOJ4066:简单题——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4066
https://www.luogu.com.cn/problem/P4148
你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
命令
参数限制
内容
1 x y A
1<=x,y<=N,A是正整数
将格子x,y里的数字加上A
2 x1 y1 x2 y2
1<=x1<= x2<=N
1<=y1<= y2<=N
输出x1 y1 x2 y2这个矩形内的数字和
3
无
终止程序
K-D树板子题,好的我重写了一个多小时的板子。
1操作就正常加点,2操作类似线段树一样查询,如果当前区间所有点都在这里面那就全加上,否则看是否区域有重叠,如果没有那么肯定没有贡献直接结束,否则往下遍历。
然后插入的时候请像替罪羊树那样拍扁重建,注意重建的点数据清空(比如它的左右儿子),我就是因为这个debug了1h+……
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef double dl; typedef long long ll; const int K=2; const int N=2e5+5; const dl alpha=0.7; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } int D,n,tot,num,root,rubbish[N]; struct Point{ int d[K],w; bool operator <(const Point &a)const{ return d[D]<a.d[D]; } }a[N]; struct KDTREE{ int s[2],x[2],y[2]; int sz,sum; Point p; }tr[N]; #define ls tr[o].s[0] #define rs tr[o].s[1] #define cmax(a,b) (a<b?a=b:a) #define cmin(a,b) (a>b?a=b:a) inline int newnode(){ if(!tot)return ++n; return rubbish[tot--]; } inline void upd(int f,int x){ cmin(tr[f].x[0],tr[x].x[0]),cmax(tr[f].x[1],tr[x].x[1]); cmin(tr[f].y[0],tr[x].y[0]),cmax(tr[f].y[1],tr[x].y[1]); } inline void pushup(int o){ tr[o].x[0]=tr[o].x[1]=tr[o].p.d[0]; tr[o].y[0]=tr[o].y[1]=tr[o].p.d[1]; tr[o].sz=tr[ls].sz+tr[rs].sz+1; tr[o].sum=tr[ls].sum+tr[rs].sum+tr[o].p.w; if(ls)upd(o,ls);if(rs)upd(o,rs); } int build(int l,int r,int d){ D=d;int mid=(l+r)>>1; nth_element(a+l,a+mid,a+r+1); int o=newnode(); tr[o].p=a[mid]; if(l<mid)ls=build(l,mid-1,d^1),upd(o,ls);else ls=0; if(mid<r)rs=build(mid+1,r,d^1),upd(o,rs);else rs=0; pushup(o);return o; } void slap(int o){ if(ls)slap(ls); a[++num]=tr[o].p;rubbish[++tot]=o; if(rs)slap(rs); } inline void check(int &o,int d){ if(alpha*tr[o].sz<tr[ls].sz||alpha*tr[o].sz<tr[rs].sz) num=0,slap(o),o=build(1,num,d); } void insert(int &o,Point x,int d){ if(!o){ o=newnode();tr[o].p=x;pushup(o); return; } if(x.d[d]<=tr[o].p.d[d])insert(ls,x,d^1); else insert(rs,x,d^1); pushup(o);check(o,d); } inline bool inside(int o,Point x,Point y){ return x.d[0]<=tr[o].x[0]&&tr[o].x[1]<=y.d[0] &&x.d[1]<=tr[o].y[0]&&tr[o].y[1]<=y.d[1]; } inline bool outside(int o,Point x,Point y){ return x.d[0]>tr[o].x[1]||tr[o].x[0]>y.d[0] ||x.d[1]>tr[o].y[1]||tr[o].y[0]>y.d[1]; } int query(int o,Point x,Point y){ if(!o)return 0; if(inside(o,x,y))return tr[o].sum; if(outside(o,x,y))return 0; int ans=0; if(x.d[0]<=tr[o].p.d[0]&&tr[o].p.d[0]<=y.d[0] &&x.d[1]<=tr[o].p.d[1]&&tr[o].p.d[1]<=y.d[1]) ans=tr[o].p.w; return ans+query(ls,x,y)+query(rs,x,y); } int main(){ int m=read(),lans=0; while(1){ int op=read(); if(op==1){ int x=read()^lans,y=read()^lans,A=read()^lans; insert(root,(Point){x,y,A},0); } if(op==2){ int x1=read()^lans,y1=read()^lans; int x2=read()^lans,y2=read()^lans; printf("%d\n",lans=query(root,(Point){x1,y1,0},(Point){x2,y2,0})); } if(op==3)return 0; } }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++