lhxsb(cdq分治+单调栈)

题目大意:

有删点,动态的询问一个点向左向右能看到的最远的点。

题解:

假设没有删点,这个显然可以直接单调栈前后扫两遍搞定。

如果有了删点,考虑cdq分治。

cdq分治搞不了删点,倒着变成加点。

第一维是时间,第二维是x

对于分治到区间(l,r),设m=l+r>>1

cdq分治让我们只用去处理[l..m]的插入对[m+1..r]的询问的影响。

强行建出单调栈,求能看到的最远的点由于不能把询问的点加入单调栈,所以要套上一个二分。

Code:

#include
#include
#include
#define db double
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;

const db pi = acos(-1);

const int N = 2e5 + 5;

int n, Q, x, del[N], tot, z[N];
struct node {
    int x, y, i;
} a[N], b[N];
db ans[N][2];

int cmp(node a, node b) {return a.x < b.x;}
int cmp2(node a, node b) {return a.y < b.y;}

db ji(node a, node b) {return (db) (a.y - b.y) / (a.x - b.x);}
db jj(int x, int y) {return ji(a[x], a[y]);}
void in1(int x) {
    while(z[0] > 1 && jj(z[z[0] - 1], z[z[0]]) < jj(z[z[0]], x))
        z[0] --;
    z[++ z[0]] = x;
}
void in2(int x) {
    while(z[0] > 1 && jj(z[z[0] - 1], z[z[0]]) > jj(z[z[0]], x))
        z[0] --;
    z[++ z[0]] = x;
}

void cdq(int x, int y) {
    if(x == y) return;
    int m = x + y >> 1;
    cdq(x, m); cdq(m + 1, y);
    sort(b + x, b + m + 1, cmp2); sort(b + m + 1, b + y + 1, cmp2);
    z[0] = 0; int l = x - 1;
    fo(i, m + 1, y) if(b[i].i) {
        while(l < m && b[l + 1].y < b[i].y)
            if(!b[++ l].i) in1(b[l].y);
        int as = z[0];
        for(int l = 1, r = z[0] - 1; l <= r; ) {
            int m = l + r >> 1;
            if(ji(a[z[m]], a[b[i].y]) < ji(a[z[m + 1]], a[b[i].y]))
                as = m, r = m - 1; else l = m + 1;
        }
        if(as) ans[b[i].i][0] = min(ans[b[i].i][0], pi / 2 + atan(ji(a[z[as]], a[b[i].y])));
    }
    z[0] = 0; l = m + 1;
    fd(i, y, m + 1) if(b[i].i) {
        while(l > x && b[l - 1].y > b[i].y)
            if(!b[-- l].i) in2(b[l].y);
        int as = z[0];
        for(int l = 1, r = z[0] - 1; l <= r; ) {
            int m = l + r >> 1;
            if(jj(z[m], z[m + 1]) > ji(a[z[m + 1]], a[b[i].y]))
                as = m, r = m - 1; else l = m + 1;
        }
        if(as) ans[b[i].i][1] = min(ans[b[i].i][1], pi / 2 - atan(ji(a[z[as]], a[b[i].y])));
    }
}

int main() {
    freopen("a.in", "r", stdin);
    scanf("%d %d", &n, &Q);
    fo(i, 1, n) scanf("%d %d", &a[i].x, &a[i].y), a[i].i = i;
    sort(a + 1, a + n + 1, cmp);
    tot = Q;
    fo(i, 1, Q) {
        scanf("%d %d", &b[i].x, &b[i].y);
        if(b[i].x == 0) del[b[i].y] = 1; else b[i].i = i;
        ans[i][0] = ans[i][1] = 1e9;
    }
    fo(i, 1, n) if(!del[i]) b[++ tot].x = 0, b[tot].y = i;
    fo(i, 1, tot / 2) swap(b[i], b[tot - i + 1]);
    cdq(1, tot);
    fo(i, 1, Q) if(ans[i][0] != 1e9)
        printf("%.6lf\n", ans[i][0] + ans[i][1]);
}

你可能感兴趣的:(单调队列,&&,单调栈,cdq分治)