BZOJ 4066 简单题(KD树)

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4066

【题目大意】

  要求维护矩阵内格子加点和矩阵查询

【题解】

  往KD树上加权值点,支持矩阵查询即可,每隔5000个插入暴力重构树。

【代码】

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=300000,INF=1e9;
namespace KD_Tree{
    struct Dot{
        int d[2],mn[2],mx[2],l,r,sz,sum,val;
        Dot(){l=r=0;}
        Dot(int x,int y,int c){d[0]=x;d[1]=y;val=c;l=r=sz=sum=0;}
        int& operator [] (int x){return d[x];}
    };
    int D,dcnt=0,pt[N];
    Dot T[N];
    inline void umax(int&a,int b){if(a<b)a=b;}
    inline void umin(int&a,int b){if(a>b)a=b;}
    inline bool cmp(int x,int y){return T[x][D]<T[y][D];}
    inline void up(int x){
        T[x].sz=T[T[x].l].sz+T[T[x].r].sz+1;
        T[x].sum=T[T[x].l].sum+T[T[x].r].sum+T[x].val;
        T[x].mn[0]=T[x].mx[0]=T[x][0];
        T[x].mn[1]=T[x].mx[1]=T[x][1];
        if(T[x].l){
            umax(T[x].mx[0],T[T[x].l].mx[0]);
            umin(T[x].mn[0],T[T[x].l].mn[0]);
            umax(T[x].mx[1],T[T[x].l].mx[1]);
            umin(T[x].mn[1],T[T[x].l].mn[1]);
        }
        if(T[x].r){
            umax(T[x].mx[0],T[T[x].r].mx[0]);
            umin(T[x].mn[0],T[T[x].r].mn[0]);
            umax(T[x].mx[1],T[T[x].r].mx[1]);
            umin(T[x].mn[1],T[T[x].r].mn[1]);
        }
    }
    inline int NewDot(int x,int y,int c){
        ++dcnt; pt[dcnt]=dcnt;
        T[dcnt][0]=x; T[dcnt][1]=y; T[dcnt].val=c;
        return up(dcnt),dcnt;
    }
    // 查询矩阵内数字和
    int query(int x,int x0,int y0,int x1,int y1){
        if(!x||T[x].mn[0]>x1||T[x].mx[0]<x0||T[x].mn[1]>y1||T[x].mx[1]<y0)return 0;
        if(T[x].mn[0]>=x0&&T[x].mx[0]<=x1&&T[x].mn[1]>=y0&&T[x].mx[1]<=y1)return T[x].sum;
        int res=0;
        if(T[x][0]>=x0&&T[x][0]<=x1&&T[x][1]>=y0&&T[x][1]<=y1)res+=T[x].val;
        return res+query(T[x].l,x0,y0,x1,y1)+query(T[x].r,x0,y0,x1,y1);
    }
    void Insert(int&x,int D,const Dot&p){
        if(!x){x=NewDot(p.d[0],p.d[1],p.val);return;}
        if(p.d[D]<T[x][D])Insert(T[x].l,D^1,p);
        else Insert(T[x].r,D^1,p);
        up(x);
    }
    // 暴力重构
    int Rebuild(int l,int r,int now){
        if(l>r)return 0;
        int mid=(l+r)>>1,x;
        D=now;
        nth_element(pt+l,pt+mid,pt+r+1,cmp);
        x=pt[mid];
        T[x].l=Rebuild(l,mid-1,now^1);
        T[x].r=Rebuild(mid+1,r,now^1);
        return up(x),x;
    }
}
int n,op,x0,y0,x1,y1,c,ans=0,root=0;
int main(){
    scanf("%d",&n);
    while(scanf("%d",&op)){
        if(op==3)break;
        if(op==1){
            scanf("%d%d%d",&x0,&y0,&c);
            x0^=ans,y0^=ans,c^=ans;
            KD_Tree::Insert(root,0,KD_Tree::Dot(x0,y0,c));
            if(KD_Tree::dcnt%5000==0)root=KD_Tree::Rebuild(1,KD_Tree::dcnt,0);
        }else{
            scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
            x0^=ans,y0^=ans,x1^=ans,y1^=ans;
            printf("%d\n",ans=KD_Tree::query(root,x0,y0,x1,y1));
        }
    }return 0;
}
时间: 2024-10-21 03:30:16

BZOJ 4066 简单题(KD树)的相关文章

bzoj 4066: 简单题 kd-tree

4066: 简单题 Time Limit: 50 Sec  Memory Limit: 20 MBSubmit: 234  Solved: 82[Submit][Status][Discuss] Description 你有一个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

[bzoj 4066]简单题

传送门 Description 两个操作,往一个格子里加一个数和求给定矩形的权值和,强制在线,操作数\(\leq 200000\) Solution? 直接上KD-tree 为了保证树的形态较为优美 每加入\(10000\)个数后,对KD-tree进行重构 Code? #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a

【BZOJ2683】简单题 [分治][树状数组]

简单题 Time Limit: 50 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 你有一个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

bzoj 2683: 简单题

2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1779  Solved: 720[Submit][Status][Discuss] Description 你有一个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<

BZOJ 2683 简单题 ——CDQ分治

简单题 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define maxn 2000005 int sum[maxn]; void a

BZOJ 2508 简单题 数学算法

题目大意:维护一个平面,支持三种操作: 0.加入一条直线(给的是两点式) 1.删除一条直线 2.询问到所有直线距离平方和最小的点 题解见 http://blog.sina.com.cn/s/blog_ab8386bc0101i1nj.html 我只是贴代码供参考的- - 注意我的abcdef和题解设的不一样- - 这简单题WA了两页- - #include <cmath> #include <cstdio> #include <cstring> #include <

bzoj 3687: 简单题

3687: 简单题 Time Limit: 10 Sec  Memory Limit: 512 MB Description 小呆开始研究集合论了,他提出了关于一个数集四个问题:1.子集的异或和的算术和.2.子集的异或和的异或和.3.子集的算术和的算术和.4.子集的算术和的异或和.    目前为止,小呆已经解决了前三个问题,还剩下最后一个问题还没有解决,他决定把这个问题交给你,未来的集训队队员来实现. Input 第一行,一个整数n.第二行,n个正整数,表示01,a2….,. Output 一行

BZOJ 2683 简单题 cdq分治+树状数组

题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后,二维的数据结构是显然不能过的,于是我们可能会考虑把一维排序之后另一位上数据结构什么的,然而cdq分治却能够很好的体现它的作用. 首先,对于每一个询问求和,显然是x在它左边的并且出现时间在它之前的所有的change对他可能会有影响. 我们按照x第一关键字,y第二关键字,操作第三关键字来排序所有的询问,然后在cdq的时候,每次递归处理左半区间,按照x动态的将y这一列的值加到树状数组里,来更新右半边的所有询问,注意这

bzoj 2683 简单题 cdq分治

题面 题目传送门 解法 可以离线,那么就是非常简单的cdq分治了 只要把询问拆成4个,然后就变成了一个三维偏序问题 时间复杂度:\(O(q\ log^2\ n)\) 代码 #include <bits/stdc++.h> #define int long long #define N 1000010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y