洛谷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/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2020-02-09 15:52  luyouqi233  阅读(170)  评论(0编辑  收藏  举报