[BZOJ2716][天使玩偶angel][CDQ分治]

来源:互联网 发布:网络平台合作推广方案 编辑:程序博客网 时间:2024/05/01 10:35

[BZOJ2716][天使玩偶angel][CDQ分治]

题目大意:

先给出n个点, 然后有m个操作, (1, x, y) 表示查询离(x, y)最近点的曼哈顿距离, (2, x, y) 表示插入点 (x, y)。

CDQ分治相关:

这道题在线的话是可以用KD-Tree维护平面上的点集。但是既然题目没有要求在线那就用CDQ分治做好了。

CDQ分治是一种离线的分治算法。对于一个数据结构问题,无非存在两种操作:修改查询。但是修改和查询往往都是动态的,也就是存在时间维度上的限制,要进行某一个查询,就一定要处理在这个查询之前的所有修改。而CDQ分治可以打破这一维的限制,使得动态查询变为静态查询。用到的方法就是对于一个询问,将它和所有和它有关的修改联系在一起。

(值得注意的是:这一维并不一定是时间上的限制,也有可能是别的。比如BZOJ3262 陌上花开。)

首先我们定义Divide(L,R),表示处理完了区间[L,R]中修改对于查询的影响。首先我们引入分治的思想,将区间[L,R]分为[L,mid][mid+1,R],首先处理Divide(L,mid),然后处理[L,mid]中修改对于查询的影响,最后处理Divide(mid+1,R)

可以看出,[mid+1,R]中的修改并不会影响到[L,mid]中的询问,而在[mid+1,R]中的询问被[L,mid][mid+1,R](后者会继续分治将范围缩小)所共同影响。假设处理前半区间修改对后半区间查询的复杂度为O(f(n))。那么总时间复杂度为O(f(n)logn)。也就是说,CDQ分治用了O(logn)的代价打破了时间维度的限制。

思路:

容易看出这道题的修改和查询操作分别为1和2。

我们要把和查询有关的修改整理成某个查询的前缀,在这道题里总共有三个限制timexy。其中(x,y)因为可以在查询点的任意方位不好搞,需要进行分类讨论,每次只考虑查询左上,右上,左下,右下之中的一个方位的最小曼哈顿距离,然后对于四次求出的答案中取Min即可。

考虑到编码方便

  • 右上,左上和右下都可以由原平面水平和竖直翻转得到,只需要编码左下一个方位。

  • 曼哈顿距离的计算方法为:dist((x,y),(x,y))=|xx|+|yy|,当只考虑左下方位时可以去掉绝对值,原式转化为dist((x,y),(x,y))=x+y(y+x)。即在询问(x,y)的所有修改前缀(x,y)中,我们要求Max(x+y)

  • 可以用数组数组维护区间最大值

Q:前面说到CDQ分治只能取消time一维的限制啊,还有xy的限制怎么说?再套两个CDQ吗?

A:哈,不存在的,x直接排序,树状数组插入下标用y

坑:

翻转时要保证翻转后的点集x>0,y>0,不然算lowbit(x)的时候直接死循环……

代码:

#include <bits/stdc++.h>const int Maxn = 1000010;const int INF = 1 << 30;using namespace std;inline int Max(const int &a, const int &b) {    return a > b ? a : b;}inline int Min(const int &a, const int &b) {    return a < b ? a : b;}inline char get(void) {    static char buf[1000000], *p1 = buf, *p2 = buf;    if (p1 == p2) {        p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);        if (p1 == p2) return EOF;    }    return *p1++;}inline void read(int &x) {    x = 0; static char c; bool minus = false;    for (; !(c >= '0' && c <= '9'); c = get()) if (c == '-') minus = true;    for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); if (minus) x = -x;}struct Abcd {    int x, y, k, id;    friend bool operator <  (const Abcd &a, const Abcd &b) {        if (a.x == b.x) return a.id < b.id;        else return a.x < b.x;    }} oo[Maxn];int n, m, Mx, ans[Maxn], t[Maxn];inline void add(int x, int y) {    for (x; x <= Mx; x += x & -x) {        t[x] = Max(t[x], y);    }}inline int query(int x) {    int sum = 0;    for (; x; x -= x & -x) {        sum = Max(sum, t[x]);    }    return sum;}inline void clear(int x) {    for (x; x <= Mx; x += x & -x) {        t[x] = 0;    }}struct Cdq {    Abcd T[Maxn];    int n;    inline void init(const int &n) {        this->n = n;        sort(oo + 1, oo + 1 + n);    }    inline void solve(int L, int R) {        if (L >= R) return;        int mid = (L + R) >> 1, i = L, j = mid + 1;        for (int k = L; k <= R; k++) {            if (oo[k].id <= mid) T[i++] = oo[k];            else T[j++] = oo[k];        }        for (int k = L; k <= R; k++) oo[k] = T[k];        solve(L, mid);        i = L, j = mid + 1;        for (; j <= R; j++) if (oo[j].k == 2) {            for (; i <= mid && oo[i].x <= oo[j].x; i++) if (oo[i].k == 1) {                add(oo[i].y, oo[i].x + oo[i].y);            }            int tmp = query(oo[j].y);            if (tmp) ans[oo[j].id] = Min(ans[oo[j].id], oo[j].x + oo[j].y - tmp);        }        for (j = L; j < i; j++)            if (oo[j].k == 1) clear(oo[j].y);        solve(mid + 1, R);        merge(oo + L, oo + mid + 1, oo + mid + 1, oo + R + 1, T + L);        for (int i = L; i <= R; i++) oo[i] = T[i];    }} cdq;int main(void) {    //freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);    read(n), read(m);    for (int i = 1; i <= n; i++) {        read(oo[i].x), read(oo[i].y);        Mx = Max(Mx, Max(++oo[i].x, ++oo[i].y));        oo[i].id = i;        oo[i].k = 1;    }    for (int i = n + 1; i <= n + m; i++) {        read(oo[i].k), read(oo[i].x), read(oo[i].y);        Mx = Max(Mx, Max(++oo[i].x, ++oo[i].y));        oo[i].id = i;    }    for (int i = 1; i <= n + m; i++) ans[i] = INF;    Mx++;    cdq.init(n + m);    cdq.solve(1, n + m);    for (int i = 1; i <= n + m; i++) oo[i].x = Mx - oo[i].x;    cdq.init(n + m);    cdq.solve(1, n + m);     for (int i = 1; i <= n + m; i++) oo[i].y = Mx - oo[i].y;    cdq.init(n + m);    cdq.solve(1, n + m);    for (int i = 1; i <= n + m; i++) oo[i].x = Mx - oo[i].x;    cdq.init(n + m);    cdq.solve(1, n + m);    for (int i = 1; i <= n + m; i++)        if (ans[i] != INF)             printf("%d\n", ans[i]);    return 0;}

完。

By g1n0st

1 0
原创粉丝点击