SRM 562 Div1 500 CheckerFreeness

25 篇文章 0 订阅
16 篇文章 0 订阅
/*
    通过枚举一对黑点(l,r)。
    我们可以计算出其他所有白点和他们的相对位置(用叉积表示) 
    我们把剩余的白点以和直线(l,r)的左右位置分成两部分 
    我们用pos表示在线段l -> r左侧的点,其相对于l,相对于r,分别是顺时针第pos[i].fr, pos[i].sc个点。
    lim表示在l -> r右侧的点,与它,选中的l,r,能形成凸多边形的左侧点,需要满足fr  >= lim[i].fr, sc <= lim[i].sc
    然后我们对pos和lim进行排序 
    之后我们利用树状数组,把pos中fr>=lim[i].fr的不断sc加入树状数组后,如果从树状数组中找到了对于lim[i]合法的sc时就得到了答案
*/
#include<bits/stdc++.h>   
#define cl(x) memset(x, 0, sizeof(x));
#define pii pair<int, int>
#define fr first
#define sc second
#define M 250
typedef long long ll;
using namespace std;
int n,m;
bool side[M]; // side[i] = 1,表示第i个点在线段l -> r的左侧 
struct poi{
    int x, y, id;
    poi(){}
    poi(int _x, int _y) { x = _x; y = _y; }
    poi operator + (const poi &b) { return poi(x + b.x, y + b.y); }
    poi operator - (const poi &b) { return poi(x - b.x, y - b.y); }
    ll  operator * (const poi &b) { return 1ll * x * b.y - 1ll * y * b.x; } // 叉积
}W[M],B[M],tmp[M]; // 存白点相对于被选中的两个黑点的坐标;
bool operator < (poi a, poi b) {
    return a * b < 0; 
}
pii pos[M], lim[M]; 
//pos表示在线段l -> r左侧的点,其相对于l,相对于r,分别是顺时针第pos[i].fr, pos[i].sc个点。
//lim表示在l -> r右侧的点,与它,选中的l,r,能形成凸多边形的左侧点,需要满足fr  >= lim[i].fr, sc <= lim[i].sc
int c[M]; // 树状数组
void add(int x) { // 单点加
    for (int i = x; i <= n; i += (i & (-i)))++c[i];
}
int get(int x) { // 前缀和
    int ret = 0;
    for (int i = x; i; i -= (i & (-i))) ret += c[i];
    return ret;
}
bool cmp(const pii &a, const pii &b) {
    return a.fr == b.fr ? a.sc < b.sc : a.fr > b.fr; 
}
bool check(poi l, poi r) { // 选择l,r两个黑点为对角上的黑点
    int k = 0, p = 0;
    for (int i = 1; i <= n; ++i)
        side[i]=((W[i] - r) * (l - r) > 0ll); // 判断白点在两个黑点的哪一侧
    for (int i = 1; i <= n; ++i)
        if (side[i]) tmp[++k] = W[i] - l, tmp[k].id = k; // 计算相对l的极角
    sort(tmp + 1, tmp + k + 1); // 因为都在pi的范围内,所以可以直接用叉积来排序
    for (int i = 1; i <= k; ++i) pos[tmp[i].id].fr = i; // 确定下相对l极角序的排名
    for (int i = 1; i <= n; ++i)
        if (!side[i])lim[++p].fr = upper_bound(tmp + 1, tmp + k + 1, l - W[i]) - tmp; // 确定下对应的左侧点,相对l的极角序至少要排在第几位

    k = 0; p = 0; // 同理计算相对r的极角序
    for (int i = 1; i <= n; ++i)
        if (side[i]) tmp[++k] = W[i] - r, tmp[k].id = k;
    sort(tmp + 1, tmp + k + 1);
    for (int i = 1; i <= k; ++i) pos[tmp[i].id].sc = i;
    for (int i = 1; i <= n; ++i)
        if (!side[i])lim[++p].sc = lower_bound(tmp + 1, tmp + k + 1, r - W[i]) - tmp - 1;

    cl(c);
    sort(pos + 1, pos + k + 1, cmp); int tp = 1;  
    sort(lim + 1, lim + p + 1, cmp); // 都根据两维关键字排序
    for (int i = 1; i <= p; ++i) {
        while (tp <= k && pos[tp].fr >= lim[i].fr) // 把fr这维满足条件的左侧点加入树状数组的sc位置
            add(pos[tp++].sc);
        if (get(lim[i].sc)) return 1; // 存在满足条件的点
    }return 0;
}
int main(){ 
    scanf("%d",&n);
    for (int i = 1; i <= n; ++i) scanf("%d",&W[i].x);
    for (int i = 1; i <= n; ++i) scanf("%d",&W[i].y);
    scanf("%d",&m);
    for (int i = 1; i <= m; ++i) scanf("%d",&B[i].x);
    for (int i = 1; i <= m; ++i) scanf("%d",&B[i].y);
    for (int i = 1; i <= m; ++i)
        for (int j = i + 1; j <= m; ++j)
            if (check(B[i], B[j])){puts("NO");return 0;}
    puts("YES");
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值