简单题(K-D Tree)

简单题不简单……

我们把单点加操作改成插入一个权值为增加量的点,将问题转化成询问一个矩阵中所有点的和,用 \(K-D\ Tree\) 维护,时间复杂度 \(O(n\sqrt{n})\)

\(Code\ Below:\)

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int maxn=500000+10;
const double alpha=0.75;
int n,D,rt,cnt,tot,rub[maxn],top;

struct node{
    int d[2],val;
}a[maxn];
inline bool operator < (const node &a,const node &b){
    return a.d[D]<b.d[D];
}

struct KD_Tree{
    int d[2],Max[2],Min[2],ch[2],val,siz,sum;
    inline void init(){
        d[0]=d[1]=Max[0]=Max[1]=Min[0]=Min[1]=ch[0]=ch[1]=val=siz=sum=0;
    }
    inline void get(node a){
        Max[0]=Min[0]=d[0]=a.d[0];
        Max[1]=Min[1]=d[1]=a.d[1];
        siz=1;val=sum=a.val;
    }
}t[maxn];

inline int read(){
    register int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return (f==1)?x:-x;
}

inline int newnode(){
    int x=top?rub[top--]:++cnt;
    t[x].init();return x;
}

inline void update(int x,int y){
    t[x].Max[0]=max(t[x].Max[0],t[y].Max[0]);
    t[x].Max[1]=max(t[x].Max[1],t[y].Max[1]);
    t[x].Min[0]=min(t[x].Min[0],t[y].Min[0]);
    t[x].Min[1]=min(t[x].Min[1],t[y].Min[1]);
}

inline void pushup(int x){
    t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;
    t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].val;
    if(t[x].ch[0]) update(x,t[x].ch[0]);
    if(t[x].ch[1]) update(x,t[x].ch[1]);
}

int build(int l,int r,int now){
    int mid=(l+r)>>1,x=newnode();D=now;
    nth_element(a+l,a+mid,a+r+1);
    t[x].get(a[mid]);
    if(l<mid) t[x].ch[0]=build(l,mid-1,now^1);
    if(mid<r) t[x].ch[1]=build(mid+1,r,now^1);
    pushup(x);return x;
}

void del(int x){
    if(t[x].ch[0]) del(t[x].ch[0]);
    a[++tot].d[0]=t[x].d[0];
    a[tot].d[1]=t[x].d[1];
    a[tot].val=t[x].val;
    rub[++top]=x;
    if(t[x].ch[1]) del(t[x].ch[1]);
}

void check(int &x,int now){
    if(1.0*max(t[t[x].ch[0]].siz,t[t[x].ch[1]].siz)>1.0*alpha*t[x].siz)
        tot=0,del(x),x=build(1,tot,now);
}

void insert(int &x,node c,int now){
    if(!x){
        x=newnode();
        t[x].get(c);
        return ;
    }
    if(c.d[now]<=t[x].d[now]) insert(t[x].ch[0],c,now^1);
    else insert(t[x].ch[1],c,now^1);
    pushup(x);check(x,now);
}

int query(int x,int x1,int x2,int y1,int y2){
    if(t[x].Max[0]<x1||t[x].Min[0]>x2||t[x].Max[1]<y1||t[x].Min[1]>y2) return 0;
    if(t[x].Max[0]<=x2&&t[x].Min[0]>=x1&&t[x].Max[1]<=y2&&t[x].Min[1]>=y1) return t[x].sum;
    int ans=0;
    if(t[x].d[0]<=x2&&t[x].d[0]>=x1&&t[x].d[1]<=y2&&t[x].d[1]>=y1) ans=t[x].val;
    if(t[x].ch[0]) ans+=query(t[x].ch[0],x1,x2,y1,y2);
    if(t[x].ch[1]) ans+=query(t[x].ch[1],x1,x2,y1,y2);
    return ans;
}

int main()
{
    n=read();
    int op,x,y,z,x1,x2,y1,y2,lastans=0;
    while(1){
        op=read();
        if(op==1){
            x=read()^lastans,y=read()^lastans,z=read()^lastans;
            insert(rt,(node){x,y,z},0);
        }
        if(op==2){
            x1=read()^lastans,y1=read()^lastans,x2=read()^lastans,y2=read()^lastans;
            printf("%d\n",lastans=query(rt,x1,x2,y1,y2));
        }
        if(op==3) break;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/owencodeisking/p/10350759.html

时间: 2024-08-28 08:01:28

简单题(K-D Tree)的相关文章

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

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

数论 --- 简单题

吃糖果 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 22376    Accepted Submission(s): 6396 Problem Description HOHO, 终于从Speakless手上赢走了所有的糖果,是Gardon吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一 种,这样:

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

HNU 12868 Island (简单题)

题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=12868&courseid=272 解题报告:输入n*m的地图,+表示土地,-表示水,要你求这个海岛的海岸线有多长,扫一遍就可以了. 1 #include<cstdio> 2 const int maxn = 2000; 3 char map[maxn][maxn]; 4 int _x[4] = {-1,0,1,0}; 5 int _y[4] = {0

hdu 1201 18岁生日 (简单题)

18岁生日 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 18281    Accepted Submission(s): 5776 Problem Description Gardon的18岁生日就要到了,他当然很开心,可是他突然想到一个问题,是不是每个人从出生开始,到达18岁生日时所经过的天数都是一样的呢?似乎并不全都是这样,所以他

bzoj3687简单题(dp+bitset优化)

3687: 简单题 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 861  Solved: 399[Submit][Status][Discuss] Description 小呆开始研究集合论了,他提出了关于一个数集四个问题:1.子集的异或和的算术和.2.子集的异或和的异或和.3.子集的算术和的算术和.4.子集的算术和的异或和.    目前为止,小呆已经解决了前三个问题,还剩下最后一个问题还没有解决,他决定把这个问题交给你,未来的集训队队员来实现

BFS简单题套路_Codevs 1215 迷宫

BFS 简单题套路 1. 遇到迷宫之类的简单题,有什么行走方向的,先写下面的 声明 const int maxn = 20; struct Status { int r, c; Status(int r = 0, int c = 0) : r(r), c(c) {} // int DIR; }; int N; //迷宫数量 int W; //迷宫宽度 char map[maxn][maxn]; //地图 //方向 : 分别代表 上.右.下.左向量 int dir[4][2] = { {-1, 0

【BZOJ-1176&amp;2683】Mokia&amp;简单题 CDQ分治

1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 821[Submit][Status][Discuss] Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小