P4148 简单题(KDTree)

传送门

KDTree
修改权值当做插入节点,不平衡就暴力重构,询问的时候判断当前节点代表的矩形是否在询问的矩形的,是的话返回答案,相离返回0,否则的话判断当前点是否在矩形内,然后继续递归下去

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;
struct point{int v[2],w;}pool[N];
struct node{int mn[2],mx[2],sum,l,r,sz;point tp;}tr[N];
int n,m,K,rt,top,cnt,st[N],ans;
inline bool operator <(const point &a,const point &b){return a.v[K]<b.v[K];}
inline int newnode(){return top?st[top--]:++cnt;}
void upd(int p){
    int l=tr[p].l,r=tr[p].r;
    fp(i,0,1){
        tr[p].mn[i]=tr[p].mx[i]=tr[p].tp.v[i];
        if(l)cmin(tr[p].mn[i],tr[l].mn[i]),cmax(tr[p].mx[i],tr[l].mx[i]);
        if(r)cmin(tr[p].mn[i],tr[r].mn[i]),cmax(tr[p].mx[i],tr[r].mx[i]);
    }tr[p].sum=tr[l].sum+tr[r].sum+tr[p].tp.w,tr[p].sz=tr[l].sz+tr[r].sz+1;
}
int build(int l,int r,int k){
    if(l>r)return 0;int mid=(l+r)>>1,p=newnode();
    K=k,nth_element(pool+l,pool+mid,pool+r+1),tr[p].tp=pool[mid];
    tr[p].l=build(l,mid-1,k^1),tr[p].r=build(mid+1,r,k^1);
    upd(p);return p;
}
void pia(int p,int sum){
    if(tr[p].l)pia(tr[p].l,sum);
    pool[sum+tr[tr[p].l].sz+1]=tr[p].tp,st[++top]=p;
    if(tr[p].r)pia(tr[p].r,sum+tr[tr[p].l].sz+1);
}
void ck(int &p,int k){
    if(tr[p].sz*0.75<tr[tr[p].l].sz||tr[p].sz*0.75<tr[tr[p].r].sz)
    pia(p,0),p=build(1,tr[p].sz,k);
}
void ins(int &p,point res,int k){
    if(!p)return (void)(p=newnode(),tr[p].l=tr[p].r=0,tr[p].tp=res,upd(p));
    res.v[k]<=tr[p].tp.v[k]?ins(tr[p].l,res,k^1):ins(tr[p].r,res,k^1);
    upd(p),ck(p,k);
}
inline bool in(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2){
    return x1<=X1&&y1<=Y1&&x2>=X2&&y2>=Y2;
}
inline bool out(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2){
    return x1>X2||x2<X1||y1>Y2||y2<Y1;
}
int query(int p,int x1,int y1,int x2,int y2){
    if(!p)return 0;int res=0;
    if(in(x1,y1,x2,y2,tr[p].mn[0],tr[p].mn[1],tr[p].mx[0],tr[p].mx[1]))return tr[p].sum;
    if(out(x1,y1,x2,y2,tr[p].mn[0],tr[p].mn[1],tr[p].mx[0],tr[p].mx[1]))return 0;
    if(in(x1,y1,x2,y2,tr[p].tp.v[0],tr[p].tp.v[1],tr[p].tp.v[0],tr[p].tp.v[1]))res+=tr[p].tp.w;
    res+=query(tr[p].l,x1,y1,x2,y2)+query(tr[p].r,x1,y1,x2,y2);return res;
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read();int op,x1,y1,x2,y2;
    while(true){
        op=read();if(op==3)break;
        if(op==1)ins(rt,(point){read()^ans,read()^ans,read()^ans},0);
        else{
            x1=read()^ans,y1=read()^ans,x2=read()^ans,y2=read()^ans;
            ans=query(rt,x1,y1,x2,y2),print(ans);
        }
    }return Ot(),0;
}

原文地址:https://www.cnblogs.com/bztMinamoto/p/10090792.html

时间: 2024-07-31 22:28:11

P4148 简单题(KDTree)的相关文章

【BZOJ4066】简单题 KDtree

[BZOJ4066]简单题 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这个矩形内的数字和 3 无 终止程序 Input 输入文件第一行一个正整数N. 接下来每行一个操作.每条命令除第

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

luogu P4148 简单题

传送门 这题真简单,直接把\(CDQ\)给ban掉了 其实数据范围比较小可以直接二维树状数组,我们看数据范围,发现点的个数比N还小,可以考虑用一些奇怪的数据结构 说的就是你,\(KD tree\) \(KD tree\)就是一个K维的二叉查找树(是吧),一维的二叉查找树就是我们所熟悉的平衡树,所以考虑用平衡树的方法维护,插入一个点就跟平衡树插一个点类似.查找的话,如果当前范围完全被查询范围完全包含就直接加上范围值,如果有交就递归处理,没交就不管 注意维护整棵\(KD tree\)使其平衡,可以考

【bzoj4066】简单题 KD-tree

题目描述 你有一个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 无 终止程序 输入 输入文件第一行一个正整数N. 接下来每行一个操作.每条命令除第一个数字之外,均要异或上一次输出的答案last_

Luogu P4148 简单题(K-D Tree)

题面 题解 因为强制在线,所以我们不能$cdq$分治,所以考虑用$KDT$,$KDT$维护一个矩阵,然后询问的时候如果当前矩形在询问区间内,直接记贡献,否则判断当前点是否在矩阵内,然后左右分别递归下去判断就行了. #include <cstdio> #include <cstring> #include <algorithm> using std::min; using std::max; using std::nth_element; typedef long lon

【BZOJ】【4066】简单题(强制在线)

KD-Tree KD-Tree的进阶姿势戳这里 http://zyfzyf.is-programmer.com/posts/92431.html 为啥有种线段树&平衡树的即视感……(树形结构的相似性?) 每次插入之后,判断下如果某个子树的size>父亲size*0.7,那么重构一下……(替罪羊树的即视感) 查询的时候,如果当前点表示的坐标范围被查询范围完全包含,则直接返回sum: 否则:当前点若在范围内则更新答案,左子树若不全在范围外则递归进入查询,右子树同理(线段树的即视感) TLE:re

BZOJ2683: 简单题(CDQ分治 + 树状数组)

BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ x\ y\ A\) \(1\le x,y \le N\),A是正整数 将格子\(x,y\)里的数字加上\(A\) \(2\ x1\ y1\ x2\ y2\) \(1\le x1\le x2\le N,1\le y1\le y2\le N\) 输出\(x1\ y1\ x2\ y2\)这个矩形内的数字

[bzoj4066/2683]简单题_KD-Tree

简单题 bzoj-4066 题目大意:n*n的棋盘,开始为均为0,支持:单点加权值,查询矩阵权值和,强制在线. 注释:$1\le n\le 5\cdot 10^5$,$1\le m \le 2\cdot 10^5$. 想法:KD-Tree裸题. 所谓KD-Tree,就是一个看起来贼牛逼实际上我觉着也贼牛逼的暴力... ... 算了,网上讲解一摞摞,不赘述. 这里我们只需要在KD-Tree上维护子树和即可.单点加的话往上更新呗,或者换成删除+插入也能过. 最后,附上丑陋的代码... ... #in

poj2105 IP Address(简单题)

题目链接:http://poj.org/problem?id=2105 Description Suppose you are reading byte streams from any device, representing IP addresses. Your task is to convert a 32 characters long sequence of '1s' and '0s' (bits) to a dotted decimal format. A dotted decima