您的位置:首页 > 其它

[BZOJ4605]崂山白花蛇草水(主席树套kd-tree)

2016-05-24 22:55 309 查看
题意:两种操作,在二维平面插入一个点及其权值,查询矩形区间第k大,强制在线。

之前考试考过一个矩形区间第k大的题。。当时想了各种树套树套树,算了算复杂度都没有暴力快。。后来憋了个kd-tree套主席树,就是把若干个kd-tree上的节点上的主席树弄来一起走,时间复杂度logn*sqrt(n),空间复杂度俩log(由于那个题是离线的,我当时写的kd-tree上自底向上的线段树合并,所以实际空间复杂度只有一个log)。。当时标程给的块状链表套划分树(维度高了什么奇葩玩意都有),比我慢一倍。。然后前两天BZOJ上加了俩差不多的题,就把当时的代码改了改交了一发,结果被claris狂D了一顿。。于是决心痛改前非把主席树放外面。。

主席树放外面的好处就是空间上少个log,并且不用将一大堆主席树节点存在数组里一起跑。。维度比较高的题目当中最好把平衡树或者kd-tree(本质和平衡树差不多)放里面,这样内部插入一个节点的内存开销是O(1)的。感觉主席树放外面本质其实就是动态版的划分树,因为划分树里面是数组,不支持一些动态操作,所以根据具体题目改成平衡树啊kd-tree啊什么什么的就好了。。

开始偷懒没写重构T了一发。。

加上了替罪羊还是比claris慢三倍TAT。。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
inline void gmin(int&a, const int&b) { if(a>b)a=b; }
inline void gmax(int&a, const int&b) { if(a<b)a=b; }
const int MAXN = 100005;
const int inf = 1000000000;
const int MAXS = 2000000;
const double alp = 0.8;
int N, Q;

struct dot {
int d[2], mn[2], mx[2], l, r, sz;
dot () { l = r = 0; }
dot (int x, int y) { d[0] = x; d[1] = y; l = r = 0; }
int& operator [] (int x) { return d[x]; }
};
int D, pt[MAXN];
int dcnt, tot;
namespace kdt
{
dot tr[MAXS];
inline bool cmp(int i, int j)
{
return tr[i][D] < tr[j][D];
}
inline void pushup(int k)
{
dot&l = tr[tr[k].l], &r = tr[tr[k].r];
tr[k].mn[0] = tr[k].mx[0] = tr[k][0];
tr[k].mn[1] = tr[k].mx[1] = tr[k][1];
rep(i, 0, 1)
{
if (tr[k].l) gmin(tr[k].mn[i], l.mn[i]), gmax(tr[k].mx[i], l.mx[i]);
if (tr[k].r) gmin(tr[k].mn[i], r.mn[i]), gmax(tr[k].mx[i], r.mx[i]);
}
tr[k].sz = l.sz + r.sz + 1;
}
inline int NewDot(int x, int y)
{
++dcnt, tr[dcnt][0] = x, tr[dcnt][1] = y;
return pushup(dcnt), dcnt;
}
inline bool isbad(int x)
{
return max(tr[tr[x].l].sz, tr[tr[x].r].sz) > tr[x].sz*alp+5;
}
int quary(int i, int x0, int y0, int x1, int y1)
{
if (!i||tr[i].mn[0]>x1||tr[i].mx[0]<x0||tr[i].mn[1]>y1||tr[i].mx[1]<y0) return 0;
if (tr[i].mn[0]>=x0&&tr[i].mx[0]<=x1&&tr[i].mn[1]>=y0&&tr[i].mx[1]<=y1) return tr[i].sz;
int ret = 0;
if (tr[i][0]>=x0&&tr[i][0]<=x1&&tr[i][1]>=y0&&tr[i][1]<=y1) ret ++;
return ret + quary(tr[i].l, x0, y0, x1, y1) + quary(tr[i].r, x0, y0, x1, y1);
}
int gt, gtd, gtf;
void ins(int&x, int D, const dot&p)
{
if (!x) { x = NewDot(p.d[0], p.d[1]); return; }
if (p.d[D]<tr[x][D]) ins(tr[x].l, D^1, p);
else ins(tr[x].r, D^1, p);
pushup(x);
if (isbad(x)) gt = x, gtd = D, gtf = 0;
else if (gt==tr[x].l||gt==tr[x].r) gtf = x;
}
void treavel(int&x)
{
if (!x) return;
pt[++tot] = x;
treavel(tr[x].l), treavel(tr[x].r);
}
int build(int l, int r, int now)
{
if (l > r) return 0;
int mid = (l+r)>>1, x;
D = now;
nth_element(pt+l, pt+mid, pt+r+1, cmp);
x = pt[mid];
tr[x].l = build(l, mid-1, now^1);
tr[x].r = build(mid+1, r, now^1);
return pushup(x), x;
}
void deal_ins(int&x, const dot&p)
{
gt = gtf = 0, ins(x, 0, p);
if (!gt) return;
tot = 0, treavel(gt);
if (!gtf) { x = build(1, tot, gtd); return; }
if (gt==tr[gtf].l) tr[gtf].l = build(1, tot, gtd);
else tr[gtf].r = build(1, tot, gtd);
}
}

#define lch(a) ti[a].lch
#define rch(a) ti[a].rch
struct Node {
int lch, rch, rt;
} ti[MAXS];
int ncnt, root;
void ins(int&x, const dot&p, int val, int L=1, int R=inf)
{
if (!x) x = ++ncnt;
kdt::deal_ins(ti[x].rt, p);
if (L==R) return;
int mid = (L+R)>>1;
if (val<=mid) ins(lch(x), p, val, L, mid);
else ins(rch(x), p, val, mid+1, R);
}
int quary(int&x, int&x0, int&y0, int&x1, int&y1, int k, int L=1, int R=inf)
{
if (L==R) return L;
int rcnt = kdt::quary(ti[rch(x)].rt, x0, y0, x1, y1);
int mid = (L+R)>>1;
if (k<=rcnt) return quary(rch(x), x0, y0, x1, y1, k, mid+1, R);
return quary(lch(x), x0, y0, x1, y1, k-rcnt, L, mid);
}

int main()
{
//freopen("data.txt","r",stdin);
//freopen("my.out","w",stdout);
scanf("%d%d", &N, &Q);
int op, x0, y0, x1, y1, k, ans = 0, tmp;
rep(i, 1, Q)
{
scanf("%d", &op);
if (op==1)
{
scanf("%d%d%d", &x0, &y0, &k);
x0^=ans, y0^=ans, k^=ans;
dot p = dot(x0, y0);
ins(root, p, k);
}
else
{
scanf("%d%d%d%d%d", &x0, &y0, &x1, &y1, &k);
x0^=ans, y0^=ans, x1^=ans, y1^=ans, k^=ans;
tmp = kdt::quary(ti[root].rt, x0, y0, x1, y1);
if (tmp < k) puts("NAIVE!ORZzyz."), ans=0;
else printf("%d\n", ans=quary(root, x0, y0, x1, y1, k));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: