【崂山白花蛇草水】权值线段树套kd-tree

感觉自己过得十分地卡orz,大常数玩家瑟瑟发抖。 BZOJ4605 LUOGU4848

4605: 崂山白花蛇草水

Time Limit: 80 Sec  Memory Limit: 512 MB Submit: 700  Solved: 218 [Submit][Status][Discuss]

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

HINT

Source

乍一眼看到这道题,由于刚做了K远点对,第一个想法是大小根堆A*乱搞一下,看了下K的范围orz。 好吧。我们发现求第K大的那个点的瓶数,这个我们可以想到主席树。所以说理论上外层套一个KD-TREE内层一个树上主席树,每次主席树提出log个点来搞应该是可以的。但是我们很容易发现他的常数有点爆炸,因为最关键的内层树时间复杂度总要跑满。那么我们可以换一下想法,外层套一个权值线段树,维护所有权值在区间点的KD-TREE,这样我们查询的时候看一下线段树右儿子的KD-TREE被包含是否有k个递归到右边,否则递归到左边,利用kd-tree判一下矩形是否有交和矩形是否覆盖既可。 code:
// luogu-judger-enable-o2
#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>

using namespace std;
const int maxn = 100005;
const int inf = 1e9;
int n,q;
struct node{
    node *ls,*rs; int siz;
    int sx[2],sy[2]; int x,y;
}z[maxn*40],*tl,*nul,**RT,*pool[maxn];
int lj;
bool isbad(node *&p) {
    if(max(p->ls->siz,p->rs->siz)*4>p->siz*3) return 1;
    return 0;
}
struct orz{
    int xx,yy;
}sta[maxn]; int top;
void upd(node *&p) {
    p->siz=1;
    if(p->ls!=nul) {
        p->sx[0] = min(p->sx[0],p->ls->sx[0]);
        p->sx[1] = max(p->sx[1],p->ls->sx[1]);
        p->sy[0] = min(p->sy[0],p->ls->sy[0]);
        p->sy[1] = max(p->sy[1],p->ls->sy[1]);
        p->siz+=p->ls->siz;
    }
    if(p->rs!=nul) {
        p->sx[0] = min(p->sx[0],p->rs->sx[0]);
        p->sx[1] = max(p->sx[1],p->rs->sx[1]);
        p->sy[0] = min(p->sy[0],p->rs->sy[0]);
        p->sy[1] = max(p->sy[1],p->rs->sy[1]);
        p->siz+=p->rs->siz;
    }
}
node* nwnode(int x,int y) {
    node* p = lj?pool[lj--]:++tl;
    p->ls = p->rs = nul; p->siz = 1;
    p->sx[0] = p->sx[1] = p->x = x;
    p->sy[0] = p->sy[1] = p->y = y;  
    return p;
}
void tra(node *&p) {
    if(p==nul)return;
    tra(p->ls);
    pool[++lj] = p;
    ++top;
    sta[top].xx= p->x; sta[top].yy = p->y;
    tra(p->rs);
}
bool cmpx(orz aa,orz bb) {
    return aa.xx < bb.xx ;
}
bool cmpy(orz aa,orz bb) {
    return aa.yy < bb.yy;
}
void build(node *&p,int l,int r,int nw) {
    int mid = (l+r)>>1;
    if(!nw) nth_element(sta+l,sta+mid,sta+r+1,cmpx);
    else nth_element(sta+l,sta+mid,sta+r+1,cmpy);
    p = nwnode(sta[mid].xx,sta[mid].yy);
    if(l<mid) build(p->ls,l,mid-1,nw^1);
    if(mid<r) build(p->rs,mid+1,r,nw^1);
    upd(p);
}
void rebuild() {
    if(*RT==nul) return;
    top = 0;
    tra(*RT);
    if(top>0) build(*RT,1,top,0);
    else *RT = nul;
    RT = &nul;
}

int XA,YA,XB,YB,VV;
void inskd(node *&p,int nw) {
    if(p==nul) {
        p = nwnode(XA,YA);
        return;
    }
    if(nw==0) {
        XA<=p->x?inskd(p->ls,nw^1):inskd(p->rs,nw^1);
    } else {
        YA<=p->y?inskd(p->ls,nw^1):inskd(p->rs,nw^1);
    }
    upd(p);
    if(isbad(p)) RT = &p;
}
bool panj(node *&p) {
    int xo1 = max(p->sx[0],XA);
    int yo1 = min(p->sy[1],YB);
    int xo2 = min(p->sx[1],XB);
    int yo2 = max(p->sy[0],YA);
    if(xo1<=xo2&&yo2<=yo1) return 1;
    return 0;
}
bool baohan(node *&p) {
    if(XA<=p->sx[0]&&p->sx[1]<=XB&&YA<=p->sy[0]&&p->sy[1]<=YB) return 1;
    return 0;
}
bool dianh(node *&p) {
    if(XA<=p->x&&p->x<=XB&&YA<=p->y&&p->y<=YB) return 1;
    return 0;
}
int kdquery(node *&p) {
    if(p==nul||p==NULL) return 0;
    if(!panj(p)) return 0;
    if(baohan(p)) return p->siz;
    return kdquery(p->ls) + kdquery(p->rs) + dianh(p);
}
struct nod{
    int ls,rs;
    node *rt;
}dt[maxn*40]; int tot;
int rrt;
void init() {
    tl = nul = z;
    nul->ls = nul->rs = nul;
    rrt = ++tot; dt[rrt].rt = nul;
    RT = &nul;
}
void zxins(int &p,int l,int r) {
    if(!p) {
        p = ++tot; dt[p].rt = nul;
    }
    inskd(dt[p].rt,0);
    if(*RT!=nul) rebuild();
    if(l==r) return;
    int mid = (l+r)>>1;
    if(VV<=mid) zxins(dt[p].ls,l,mid);
    else zxins(dt[p].rs,mid+1,r);
}
int query(int &p,int l,int r,int k) {
    if(!p) {
        p = ++tot; dt[p].rt = nul;
    }
    if(l==r) return l;
    int mid = (l+r)>>1;
    int rsz = dt[p].rs ? kdquery(dt[dt[p].rs].rt) : 0;
    if(rsz>=k) return query(dt[p].rs,mid+1,r,k);
    else return query(dt[p].ls,l,mid,k-rsz);
}
int main() {
    init();
    scanf("%d%d",&n,&q);
    int type,k;
    int lastans = 0;
    for(int i=1;i<=q;i++) {
        scanf("%d",&type);
        if(type==1) {
            scanf("%d%d%d",&XA,&YA,&VV);
            XA^=lastans; YA^=lastans; VV^=lastans;
            zxins(rrt,1,inf);
        } else {
            scanf("%d%d%d%d%d",&XA,&YA,&XB,&YB,&k);
            XA^=lastans; YA^=lastans; XB^=lastans; YB^=lastans; k^=lastans;
            if(XA>XB) swap(XA,XB);
            if(YA>YB) swap(YA,YB);
            if( kdquery(dt[rrt].rt ) <k ) puts("NAIVE!ORZzyz."),lastans=0;
            else {
                lastans = query(rrt,1,inf,k);
                printf("%d\n",lastans);
            }
        }
    }
}
 
posted @ 2018-11-24 21:25  Newuser233  阅读(5)  评论(0)    收藏  举报