BZOJ 4605 崂山白花蛇草水 权值线段树+K-D树

3 篇文章 0 订阅
2 篇文章 0 订阅

Description

神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水。凭借着神犇Aleph的实
力,他轻松地进了山东省省队,现在便是他履行诺言的时候了。蒟蒻Bob特地为他准备了999,999,999,999,999,999
瓶崂山白花蛇草水,想要灌神犇Aleph。神犇Aleph求(跪着的)蒟蒻Bob不要灌他,由于神犇Aleph是神犇,蒟蒻Bo
b最终答应了他的请求,但蒟蒻Bob决定将计就计,也让神犇Aleph回答一些问题。具体说来,蒟蒻Bob会在一个宽敞
的广场上放置一些崂山白花蛇草水(可视为二维平面上的一些整点),然后询问神犇Aleph在矩形区域(x1, y1), (
x2, y2)(x1≤x2且y1≤y2,包括边界)中,崂山白花蛇草水瓶数第k多的是多少。为了避免麻烦,蒟蒻Bob不会在同
一个位置放置两次或两次以上的崂山白花蛇草水,但蒟蒻Bob想为难一下神犇Aleph,希望他能在每次询问时立刻回
答出答案。神犇Aleph不屑于做这种问题,所以把这个问题交给了你。

Input

输入的第一行为两个正整数N, Q,表示横纵坐标的范围和蒟蒻Bob的操作次数(包括放置次数和询问次数)。
接下来Q行,每行代表蒟蒻Bob的一个操作,操作格式如下:
首先第一个数字type,表示操作种类。type=1表示放置,type=2表示询问。
若type=1,接下来会有三个正整数x, y, v,表示在坐标整点(x, y)放置v瓶崂山白花蛇草水。(1≤x, y≤N, 1≤v≤10^9)
若type=2,接下来会有五个正整数x1, y1, x2, y2, k,表示询问矩形区域(x1, y1), (x2, y2)中,崂山白花蛇草水瓶数第k多的是多少。
(1≤x1≤x2≤N,1≤y1≤y2≤N,1≤k≤Q)
为了体现程序的在线性,你需要将每次读入的数据(除了type值)都异或lastans,其中lastans表示上次询问的答
案。如果上次询问的答案为"NAIVE!ORZzyz."(见样例输出),则将lastans置为0。初始时的lastans为0。
初始时平面上不存在崂山白花蛇草水。
本题共有12组测试数据。对于所有的数据,N≤500,000。
Q的范围见下表:
测试点1-2     Q=1,000
测试点3-7     Q=50,000
测试点8-12     Q=100,000

Output

对于每个询问(type=2的操作),回答崂山白花蛇草水瓶数第k多的是多少。若不存在第k多的瓶数,
请输出"NAIVE!ORZzyz."(输出不含双引号)。

Sample Input

10 7
1 1 1 1
1 2 2 3
1 4 1 2
1 3 4 4
2 1 1 4 1 3
2 2 2 3 5 4
2 2 1 4 4 2

Sample Output

NAIVE!ORZzyz.
NAIVE!ORZzyz.
3
麻麻我树套树一A辣!!

这题一看就是树套树的裸题啊

首先要查k小值,那么就要在外面来颗权值线段树,然后像主席树查询一样查询,那么就需要排名,排名是矩形里的点的个数,用K-D树维护一下就好了!。

代码略长

#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using std::min;
using std::max;
using std::nth_element;
const double alpha = 0.755;
const int MAXN = 100005;
const int inf = 1000000000;
int now,x0,x1,y0,y1,len,Ans,n,Q;


template<typename _t>
inline _t read(){
    _t x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
    for(;isdigit(ch);ch=getchar())x=x*10+(ch^48);
    return x*f;
}

struct Point{
    int d[2];
    inline int& operator [](int x){return d[x];}
    inline bool operator < (const Point &a)const{
        return d[now]==a.d[now]?d[now^1]<a.d[now^1]:d[now]<a.d[now];
    }
}pt[MAXN];

struct node{
    node *ls,*rs;
    Point point;
    int mn[2],mx[2],s,split;
    inline void Update(node *p){
        if(!p)return;
        for(int i=0;i<=1;i++)mn[i]=min(mn[i],p->mn[i]);
        for(int i=0;i<=1;i++)mx[i]=max(mx[i],p->mx[i]);
    }

    inline void Maintain(){
        s=1;mn[0]=mx[0]=point[0];mn[1]=mx[1]=point[1];
        if(ls)s+=ls->s,Update(ls);
        if(rs)s+=rs->s,Update(rs);
    }

    inline bool in(int x0,int y0,int x1,int y1){
        return x0<=mn[0]
        && x1>=mx[0]
        && y0<=mn[1]
        && y1>=mx[1];
    }

    inline bool out(int x0,int y0,int x1,int y1){
        return mn[0]>x1
        || mx[0]<x0
        || mn[1]>y1
        || mx[1]<y0;
    }

    inline bool self(int x0,int y0,int x1,int y1){
        return point[0]>=x0
        && point[0]<=x1
        && point[1]>=y0
        && point[1]<=y1;
    }

    node(Point x,int sp){
        split = sp;
        ls = rs= NULL;
        point = x;s=1;
        mn[0]=mx[0]=x[0];
        mn[1]=mx[1]=x[1];
    }
    node(){}

    void* operator new(size_t);
    void operator delete(void *p);

    #define size(x) ((x)?(x)->s:(0))
    inline bool bad(){return size(ls)>=s*alpha||size(rs)>=s*alpha;}
}*C,*mempool,*need;
std::vector<node*>bin;

void build(node *&o,int l,int r,int d=0){
    if(l>r){o=NULL;return;}
    now = d;int mid = l+r>>1;
    nth_element(&pt[l],&pt[mid],&pt[r+1]);
    o = new node(pt[mid],now);
    build(o->ls,l,mid-1,d^1);
    build(o->rs,mid+1,r,d^1);
    o->Maintain();
}

void* node :: operator new(size_t){
    node *p;
    if(!bin.empty()){
        p = bin.back();
        bin.pop_back();
    }
    else{
        if(C==mempool){
            C=new node[1<<15];
            mempool=C+(1<<15);
        }
        p=C++;
    }
    return p;
}

void node::operator delete(void* p){
    bin.push_back((node*)p);
}

int Query(node *o){
    if(!o)return 0;
    if(o->in(x0,y0,x1,y1))return o->s;
    if(o->out(x0,y0,x1,y1))return 0;
    int Ans = 0;
    if(o->self(x0,y0,x1,y1))Ans ++;
    return Ans+Query(o->ls)+Query(o->rs);
}

void dfs(node *p){
    if(!p)return;
    dfs(p->ls);
    pt[++len]=p->point;
    dfs(p->rs);
    delete p;
}

inline void rebuild(node *&o){
    len = 0;
    register int split = o->split;dfs(o);
    build(o,1,len,split);
}

void insert(node *&o,Point po,int d=0){
    if(!o){o=new node(po,d);return;}
    if(po[d]<o->point[d])insert(o->ls,po,d^1);
    else insert(o->rs,po,d^1);
    o->Maintain();
    if(o->bad())need = o;
}

inline void ins(node *&o,Point po){
    need = NULL;
    insert(o,po);
    if(need!=NULL)rebuild(need);
}

struct Seg_tree{
    Seg_tree *ls,*rs;
    node *root;
    Seg_tree(){
        ls=rs=NULL;
        root=NULL;
    }
}*root;

void Seg_insert(Seg_tree *&o,int l,int r,Point x,int val){
    if(!o) o = new Seg_tree();
    ins(o->root,x);
    if(l==r)return;
    int mid = l+r>>1;
    if(val<=mid)Seg_insert(o->ls,l,mid,x,val);
    else Seg_insert(o->rs,mid+1,r,x,val);
}

inline int Seg_Query(Seg_tree *o){
    if(!o)return 0;
    return Query(o->root);
}

inline void Ask(){
    x0=read<int>()^Ans,y0=read<int>()^Ans,x1=read<int>()^Ans,y1=read<int>()^Ans;
    register int k = read<int>()^Ans;
    if(Seg_Query(root)<k){
        Ans = 0;
        printf("NAIVE!ORZzyz.\n");
        return;
    }
    int l=1,r=inf;
    Seg_tree *rt=root;
    while(l<r){
        int mid = l+r>>1,ans=Seg_Query(rt->rs);
        if(k>ans)k-=ans,rt=rt->ls,r=mid;
        else rt=rt->rs,l=mid+1;
    }
    printf("%d\n",Ans=l);
}

inline void change(){
    Point cur;
    cur[0]=read<int>()^Ans;cur[1]=read<int>()^Ans;
    int val = read<int>()^Ans;
    Seg_insert(root,1,inf,cur,val);
}

int main(){
    n=read<int>();Q=read<int>();
    while(Q--){
        register int tmp = read<int>();
        if(tmp == 1)change();
        else Ask();
    }
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值