您的位置:首页 > 其它

SRM 562 Div1 500 CheckerFreeness

2017-05-04 20:13 513 查看
/*
通过枚举一对黑点(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: