NOI模拟(5.19) JSOID2T1 部落战争 (bzoj5317)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/scar_lyw/article/details/80411319

部落战争

题目背景:

5.19 模拟 JSOI2018D2T1

分析:计算几何 + 凸包

 

先得到两个图形的凸包,考虑对于第二个凸包上的一个点的坐标(x, y),如果在移动某个向量后与第一个凸包相交,考虑移动向量满足的条件,就应该是将一凸包移动向量(-x, -y)所得到的位置,这个移动后的凸包中的所有位置都是不可行的,这样对于二凸包上的每一个点,我们都可以找到对应的不可行的凸包,然后这些所有不可行位置就是二凸包坐标翻转后在每个顶点上接一个一凸包,我们只要对这些接上的凸包做一遍凸包就是所有不可行区域了,我们可以发现,这个总的凸包就是将一凸包和二凸包所有的线段按照斜率排序然后拼起来所形成的,每次判断向量只需要二分一下是否在凸包内就可以了。复杂度O((n + q)logn)

 

Source:


/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
 
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
 
///*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
 
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

inline void write(bool flag) {
    std::cout << (flag ? "1" : "0") << '\n'; 
    // (flag ? write_char('1') : write_char('0')), write_char('\n');
}

const int MAXN = 100000 + 10;

struct point {
    long long x, y;
    
    point() {}
    point(long long x, long long y) : x(x), y(y) {}

    inline point operator + (const point &a) const {
        return point(x + a.x, y + a.y);
    } 

    inline point operator - (const point &a) const {
        return point(x - a.x, y - a.y);
    }

    inline long long operator ^ (const point &a) const {
        return x * a.y - y * a.x;
    }

    inline long long dis2() const {
        return x * x + y * y;
    }
} p1[MAXN], p2[MAXN], p[MAXN << 1 | 1], cur;

inline bool comp(const point &a, const point &b) {
    long long det = (a - cur ^ b - cur);
    return (det) ? (det > 0) : (a.dis2() < b.dis2());
}

int n, m, q, x, y;

inline bool check(point a, point b, point c) {
    return (c - a ^ b - a) >= 0;
}

inline void graham(point *p, int &n) {
    for (int i = 1; i <= n; ++i)
        if (p[i].x < p[1].x || (p[i].x == p[1].x && p[i].y < p[1].y))
            std::swap(p[1], p[i]);
    std::vector<point> q;
    cur = p[1], std::sort(p + 2, p + n + 1, comp), q.push_back(p[1]);
    for (int i = 2; i <= n; ++i) {
        while (q.size() > 1 && check(q[q.size() - 2], q.back(), p[i]))  
            q.pop_back();
        q.push_back(p[i]);
    }
    n = q.size();
    for (int i = 0; i < n; ++i) p[i + 1] = q[i];
}

inline void merge(point *p1, point *p2) {
    static point v1[MAXN], v2[MAXN];
    for (int i = 1; i <= n; ++i) v1[i] = (p1[i == n ? 1 : i + 1] - p1[i]);
    for (int i = 1; i <= m; ++i) v2[i] = (p2[i == m ? 1 : i + 1] - p2[i]);
    int cnt = 1, l1 = 1, l2 = 1;
    p[1] = p1[1] + p2[1];
    while (l1 <= n && l2 <= m) 
        p[++cnt] = p[cnt - 1] + ((v1[l1] ^ v2[l2]) >= 0 ? v1[l1++] : v2[l2++]); 
    while (l1 <= n) p[++cnt] = p[cnt - 1] + v1[l1++];
    while (l2 <= m) p[++cnt] = p[cnt - 1] + v2[l2++];
}

inline bool inside(point u) {
    if ((u - p[1] ^ p[2] - p[1]) > 0 || (p[n + m] - p[1] ^ u - p[1]) > 0) 
        return false;
    int l = 1, r = n + m;
    while (l + 1 < r) {
        int mid = l + r >> 1;
        ((u - p[1] ^ p[mid] - p[1]) >= 0) ? r = mid : l = mid;
    }
    return ((p[r] - p[r - 1] ^ u - p[r - 1]) >= 0);
}

inline void solve() {
    R(n), R(m), R(q);
    for (int i = 1; i <= n; ++i) R(p1[i].x), R(p1[i].y);
    for (int i = 1; i <= m; ++i) 
        R(p2[i].x), R(p2[i].y), p2[i].x = -p2[i].x, p2[i].y = -p2[i].y;
    graham(p1, n), graham(p2, m), merge(p1, p2);
    while (q--) R(x), R(y), write(inside(point(x, y)));
}

int main() {
    // freopen("in.in", "r", stdin);
    solve();
    // flush();
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页