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

来源:互联网 发布:淘宝卖点什么好呢 编辑:程序博客网 时间:2024/05/17 04:26

题意:两种操作,在二维平面插入一个点及其权值,查询矩形区间第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].rchstruct 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;}


0 0