luogu P4148 简单题

传送门

这题真简单,直接把\(CDQ\)给ban掉了

其实数据范围比较小可以直接二维树状数组,我们看数据范围,发现点的个数比N还小,可以考虑用一些奇怪的数据结构

说的就是你,\(KD tree\)

\(KD tree\)就是一个K维的二叉查找树(是吧),一维的二叉查找树就是我们所熟悉的平衡树,所以考虑用平衡树的方法维护,插入一个点就跟平衡树插一个点类似.查找的话,如果当前范围完全被查询范围完全包含就直接加上范围值,如果有交就递归处理,没交就不管

注意维护整棵\(KD tree\)使其平衡,可以考虑替罪羊树,如果某个儿子子树大小>子树*\(alpha\)就将整棵子树暴力重构

细节详见代码 其实是不想写了

#include<bits/stdc++.h>
#define LL long long
#define db double
#define il inline
#define re register
#define ft first
#define sc second
#define mkpr make_pair

using namespace std;
const int N=2e5+10;
const db alpha=0.72;
il int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int dd;
#define lc (s[o].ch[0])
#define rc (s[o].ch[1])
struct point
{
    int a,d[2];
    bool operator < (const point &bb) const {return d[dd]<bb.d[dd];}
}pp[N];
struct node
{
    int ch[2],mi[2],ma[2],a,sz;
    point p;
    void clr(){ch[0]=ch[1]=mi[0]=mi[1]=ma[0]=ma[1]=a=sz=p.a=0;}
}s[N];
il void upd(int o,int x)
{
    s[o].mi[0]=min(s[o].mi[0],s[x].mi[0]),s[o].mi[1]=min(s[o].mi[1],s[x].mi[1]);
    s[o].ma[0]=max(s[o].ma[0],s[x].ma[0]),s[o].ma[1]=max(s[o].ma[1],s[x].ma[1]);
}
il void psup(int o)
{
    s[o].sz=s[lc].sz+s[rc].sz+1;
    s[o].a=s[lc].a+s[rc].a+s[o].p.a;
    s[o].mi[0]=s[o].ma[0]=s[o].p.d[0],s[o].mi[1]=s[o].ma[1]=s[o].p.d[1];
    if(lc) upd(o,lc);
    if(rc) upd(o,rc);
}
int st[N],tp,tt,m;
il int newnode()
{
    if(!tp) return ++tt;
    s[st[tp]].clr();
    return st[tp--];
}
void del(int o)
{
    if(lc) del(lc);
    pp[++m]=s[o].p,st[++tp]=o;
    if(rc) del(rc);
}
int bui(int l,int r,int d)
{
    if(l>r) return 0;
    dd=d;
    int mid=(l+r)>>1,o=newnode();
    nth_element(pp+l,pp+mid,pp+r+1);
    s[o].p=pp[mid];
    lc=bui(l,mid-1,d^1),rc=bui(mid+1,r,d^1);
    psup(o);
    return o;
}
void inst(int &o,int d,point a)
{
    if(!o) {o=newnode(),s[o].p=a,psup(o);return;}
    int mid=(s[o].mi[d]+s[o].ma[d])>>1;
    if(a.d[d]<=mid) inst(lc,d^1,a);
    else inst(rc,d^1,a);
    psup(o);
    if((db)s[o].sz*alpha<(db)max(s[lc].sz,s[rc].sz)) m=0,del(o),o=bui(1,m,d);
}
int quer(int o,int lx,int ly,int rx,int ry)
{
    int an=0;
    if(lx<=s[o].p.d[0]&&ly<=s[o].p.d[1]&&rx>=s[o].p.d[0]&&ry>=s[o].p.d[1]) an+=s[o].p.a;
    if(lc)
    {
        if(lx<=s[lc].mi[0]&&ly<=s[lc].mi[1]&&rx>=s[lc].ma[0]&&ry>=s[lc].ma[1]) an+=s[lc].a;
        else if(max(lx,s[lc].mi[0])<=min(rx,s[lc].ma[0])&&max(ly,s[lc].mi[1])<=min(ry,s[lc].ma[1])) an+=quer(lc,lx,ly,rx,ry);
    }
    if(rc)
    {
        if(lx<=s[rc].mi[0]&&ly<=s[rc].mi[1]&&rx>=s[rc].ma[0]&&ry>=s[rc].ma[1]) an+=s[rc].a;
        else if(max(lx,s[rc].mi[0])<=min(rx,s[rc].ma[0])&&max(ly,s[rc].mi[1])<=min(ry,s[rc].ma[1])) an+=quer(rc,lx,ly,rx,ry);
    }
    return an;
}
int n,rt,ans;

int main()
{
    n=rd();
    while(233)
    {
        int op=rd();
        if(op==1)
        {
            int x=rd()^ans,y=rd()^ans,z=rd()^ans;
            inst(rt,0,(point){z,x,y});
        }
        else if(op==2)
        {
            int lx=rd()^ans,ly=rd()^ans,rx=rd()^ans,ry=rd()^ans;
            printf("%d\n",ans=quer(rt,lx,ly,rx,ry));
        }
        else break;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/smyjr/p/10410325.html

时间: 2024-10-01 10:37:22

luogu P4148 简单题的相关文章

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

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)

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

poj 3270 Cow Sorting 置换群 简单题

假设初始状态为 a:2 3 1 5 4 6 则目标状态为 b:1 2 3 4 5 6且下标为初始状态中的3 1 2 4 5 6(a[3],a[1]...) 将置换群写成循环的形式 (2,3,1),(5,4),6就不用移动了. 移动方式2种 1:选循环内最小的数和其他len-1个数交换 2:选整个序列最小的数和循环内最小的数交换,转到1,再换回来. #include<cstdio> #include<queue> #include<algorithm> #include&

数论 --- 简单题

吃糖果 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

poj 3112 Digital Biochemist Circuit(简单题)

题目链接:http://poj.org/problem?id=3112 Digital Biochemist Circuit Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 876   Accepted: 375 Description A digital biochemist circuit (DBC) is a device composed of a set of processing nodes. Each pro

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岁生日时所经过的天数都是一样的呢?似乎并不全都是这样,所以他