Codeforces Beta Round #13 B. Letter A 计算几何

B. Letter A

在这里插入图片描述

solution

  1. 循环枚举作为横线的边,计算另外两边的距离是否为0来判断两线段是否相交;
  2. 利用向量计算另外两边的夹角,判断其是否非钝;
  3. 分别令横线切边分两线段,长度为 x , y x,y x,y , ( x < y ) ,(x<y) ,(x<y) x y ≥ 1 4 \frac{x}{y}\ge\frac{1}{4} yx41 4 x − y ≥ 0. 4x-y\ge0. 4xy0.
  4. 精度需 1 e − 8 1e^{-8} 1e8, 1 e − 6 1e^{-6} 1e6 可能更合适 d o u b l e double double g c d gcd gcd 类的问题。

p s : 第 一 道 洛 谷 黑 题 :   ) ps: 第一道洛谷黑题 : ~) ps:: )

code

/*SiberianSquirrel*//*CuteKiloFish*/
#include <bits/stdc++.h>
//#include<bits/extc++.h>
#include<ext/rope>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
#define Inv(x) quick_pow(x, mod - 2)
#define Polynomial vector<int>
#define DEBUG(x, y) cout << x << ": " << y << '\n';
#define mem(a, x) memset(a, x, sizeof a)
#define right_1_pos(x) __builtin_ffs(x)
#define left_0_num(x) __builtin_clz(x)
#define right_0_num(x) __builtin_ctz(x)
#define num_of_1(x) __builtin_popcount(x)
#define Pii pair<int, int>
#define mp_(x, y) make_pair(x, y)
#define all(v) (v).begin(), (v).end()
using ld = long double;
using ll = long long;
//using ill = __int128;
using ull = unsigned long long;
using i16 = short;
int inv2, inv3;
tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update> tr;
/*
 rb_tree_tag 和 splay_tree_tag 选择树的类型(红黑树和伸展树)
null_type//无映射(g++为null_mapped_type)
less<pii>//从小到大排序
tree_order_statistics_node_update//更新方式
tr.insert(mp_(x, y));//插入
tr.erase(mp_(x, y));//删除
tr.order_of_key(pii(x, y));//求排名
tr.find_by_order(x);//找k小值,返回迭代器
tr.join(b);//将b并入tr,前提是两棵树类型一致并且二没有重复元素
tr.split(v, b);//分裂,key小于等于v的元素属于tr,其余属于b
tr.lower_bound(x);//返回第一个大于等于x的元素的迭代器
tr.upper_bound(x);//返回第一个大于x的元素的迭代器
以上的所有操作的时间复杂度均为O(logn)
注意,插入的元素会去重,如set
*/
//-----------------------------------------------------------------IO Template
namespace StandardIO {
    template<typename T> inline void read(T &x) {
        x = 0; T f = 1;
        char c = getchar();
        for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
        for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
        x *= f;
    }

    template<typename T> inline void write(T x) {
        if (x < 0) putchar('-'), x *= -1;
        if (x >= 10) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace StandardIO;
// -------------------------------------------------------------------------------BASIC_MATH
namespace BASIC_MATH {
//    const ll mod = 998244353, mod_g = 3, img = 86583718;
    const ll mod = 10000007;
    const ld eps = 1e-8; // when use double gcd, let eps smaller(1e-4)
    const ld pi = acos(-1.0);
    const int inf = 0x3f3f3f3f;
    ll mul(ll a, ll b) { ll z = (long double) a / mod * b; ll res = (unsigned long long) a * b - (unsigned long long) z * mod; return (res + mod) % mod; }
    // O(1) quick_mul, use long double
    inline ll quick_pow(ll ans, ll p, ll res = 1) {
        for(; p; p >>= 1, ans = mul(ans, ans) % mod)
            if(p & 1) res = mul(res, ans) % mod;
        return res % mod;
    }
    double gcd(double a,double b) {
        if(fabs(b) < eps) return a;
        if(fabs(a) < eps) return b;
        return gcd(b, fmod(a,b));
    }
    int gcd(int a, int b) { return __gcd(a, b); }
    ll gcd(ll a, ll b) { return __gcd(a, b); }
    int sgn(double x) { if(fabs(x) < eps) return 0; return x > 0? 1: -1; }
    inline double sqr(double x) { return x * x; }
    struct Point {
        double x, y;
        Point() { }
        Point(double _x,double _y): x(_x), y(_y) { }
        void input() { cin >> x >> y; }
        void output() { cout << fixed << setprecision(12) << x << ' ' << y << '\n'; }
        bool operator == (Point b)const { return sgn(x - b.x) == 0 && sgn(y - b.y) == 0; }
        bool operator < (Point b)const { return sgn(x - b.x)== 0? sgn(y - b.y) < 0: x < b.x; }
        Point operator -(const Point &b)const { return Point(x - b.x, y - b.y); }
        double operator ^(const Point &b)const { return x * b.y - y * b.x; } // 叉乘
        double operator *(const Point &b)const { return x * b.x + y * b.y; } // 点乘
        double len() { return hypot(x, y); }
        double len2() { return x * x + y * y; }
        double distance(Point p) { return hypot(x - p.x, y - p.y); }
        Point operator +(const Point &b)const { return Point(x + b.x, y + b.y); }
        Point operator *(const double &k)const { return Point(x * k, y * k); }
        Point operator /(const double &k)const { return Point(x / k, y / k); }
        //`计算pa  和  pb 的夹角`
        double rad(Point a,Point b) { Point p = *this; return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) )); }
        //`化为长度为r的向量`
        Point trunc(double r) { double l = len(); if(!sgn(l))return *this; r /= l; return Point(x * r, y * r); }
        //`逆时针旋转90度`
        Point rotleft() { return Point(-y, x); }
        //`顺时针旋转90度`
        Point rotright() { return Point(y, -x); }
        //`绕着p点逆时针旋转angle`
        Point rotate(Point p, double angle) {
            Point v = (*this) - p; double c = cos(angle), s = sin(angle);
            return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
        }
    };
    struct Line {
        Point s, e;
        Line() { }
        Line(Point _s, Point _e): s(_s), e(_e) { }
        bool operator ==(Line v) { return (s == v.s) && (e == v.e); }
        //`根据一个点和倾斜角angle确定直线, 0 <= angle < pi`
        Line(Point p,double angle) {
            s = p;
            if(sgn(angle-pi/2) == 0) e = (s + Point(0, 1));
            else e = (s + Point(1, tan(angle)));
        }
        //ax + by + c = 0
        Line(double a,double b,double c) {
            if(sgn(a) == 0) {
                s = Point(0, -c / b);
                e = Point(1, -c / b);
            } else if(sgn(b) == 0) {
                s = Point(-c / a, 0);
                e = Point(-c / a, 1);
            } else {
                s = Point(0, -c / b);
                e = Point(1, (-c - a) / b);
            }
        }
        void input() { s.input(); e.input(); }
        void adjust() { if(e < s) swap(s,e); }
        double length() { return s.distance(e); }
        //`倾斜角 0 <= angle < pi`
        double angle() {
            double k = atan2(e.y - s.y, e.x - s.x);
            if(sgn(k) < 0)k += pi;
            if(sgn(k - pi) == 0) k -= pi;
            return k;
        }
        //`点和直线关系:`1 在左侧; 2 在右侧; 3 在直线上`
        int relation(Point p) {
            int c = sgn((p - s) ^ (e - s));
            if(c < 0) return 1;
            else if(c > 0) return 2;
            else return 3;
        }
        // 点在线段上的判断
        bool pointonseg(Point p) { return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0; }
        //`直线平行或重合`
        bool parallel(Line v) { return sgn((e - s) ^ (v.e - v.s)) == 0; }
        //`两线段相交判断:`2 规范相交; 1 非规范相交; 0 不相交`
        int segcrossseg(Line v) {
            int d1 = sgn((e-s)^(v.s-s));
            int d2 = sgn((e-s)^(v.e-s));
            int d3 = sgn((v.e-v.s)^(s-v.s));
            int d4 = sgn((v.e-v.s)^(e-v.s));
            if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;
            return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
                   (d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
                   (d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
                   (d4==0 && sgn((e-v.s)*(e-v.e))<=0);
        }
        //`直线和线段相交判断:`2 规范相交; 1 非规范相交; 0 不相交`
        int linecrossseg(Line v) {
            int d1 = sgn((e - s) ^ (v.s - s));
            int d2 = sgn((e - s) ^ (v.e - s));
            if((d1 ^ d2) == -2) return 2;
            return (d1 == 0 || d2 == 0);
        }
        //`两直线关系:`0 平行; 1 重合; 2 相交`
        int linecrossline(Line v) {
            if((*this).parallel(v))
                return v.relation(s)==3;
            return 2;
        }
        //`求两直线的交点``要保证两直线不平行或重合`
        Point crosspoint(Line v) {
            double a1 = (v.e-v.s)^(s-v.s);
            double a2 = (v.e-v.s)^(e-v.s);
            return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
        }
        //点到直线的距离
        double dispointtoline(Point p) { return fabs((p-s)^(e-s))/length(); }
        //点到线段的距离
        double dispointtoseg(Point p) {
            if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
                return min(p.distance(s),p.distance(e));
            return dispointtoline(p);
        }
        //`返回线段到线段的距离``相交距离为0`
        double dissegtoseg(Line v) {
            return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
        }
        //`返回点p在直线上的投影`
        Point lineprog(Point p) { return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) ); }
        //`返回点p关于直线的对称点`
        Point symmetrypoint(Point p) { Point q = lineprog(p); return Point(2*q.x-p.x,2*q.y-p.y); }
    };
}
using namespace BASIC_MATH;

bool check(Line l, Line l1, Line l2) {
    if(!l.segcrossseg(l1) || !l.segcrossseg(l2) || !l1.segcrossseg(l2)) { return false; }
    if((l1.pointonseg(l.e) && l2.pointonseg(l.s)) || (l1.pointonseg(l.s) && l2.pointonseg(l.e))) {
        if(sgn(l1.dissegtoseg(l2)) == 0) {
            Point P = l1.crosspoint(l2), A = l.s, B = l.e;
            if(l1.e == l2.e) P = l1.e;
            else if(l1.e == l2.s) P = l1.e;
            else if(l1.s == l2.e) P = l1.s;
            else if(l1.s == l2.s) P = l1.s;
            else return false;
            double x, y, xx, yy;
            if(l1.pointonseg(l.e) && l2.pointonseg(l.s)) {
                x = l.e.distance(l1.e), y = l.e.distance(l1.s);
                xx = l.s.distance(l2.e), yy = l.s.distance(l2.s);
            } else {
                x = l.e.distance(l2.e), y = l.e.distance(l2.s);
                xx = l.s.distance(l1.e), yy = l.s.distance(l1.s);
            }
            if(x > y) swap(x, y);
            if(xx > yy) swap(xx, yy);
            return sgn(pi / 2.0 - P.rad(A, B)) >= 0 && sgn(4 * x - y) >= 0 && sgn(4 * xx - yy) >= 0;
        } else return false;
    } else return false;

}

void solve() {
    int o; cin >> o; while(o --) {
        Line l[4]; for(int i = 1; i <= 3; ++ i) l[i].input();
        if(!l[3].segcrossseg(l[1]) || !l[3].segcrossseg(l[2]) || !l[1].segcrossseg(l[2])) { cout << "NO" << '\n'; continue; }
        if(check(l[1], l[2], l[3])) { cout << "YES" << '\n'; continue; }
        if(check(l[2], l[1], l[3])) { cout << "YES" << '\n'; continue; }
        if(check(l[3], l[1], l[2])) { cout << "YES" << '\n'; continue; }
        cout << "NO" << '\n';
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
    signed test_index_for_debug = 1;
    char acm_local_for_debug = 0;
    do {
        if (acm_local_for_debug == '$') exit(0);
        if (test_index_for_debug > 20)
            throw runtime_error("Check the stdin!!!");
        auto start_clock_for_debug = clock();
        solve();
        auto end_clock_for_debug = clock();
        cout << "Test " << test_index_for_debug << " successful!" << endl;
        cerr << "Test " << test_index_for_debug++ << " Run Time: "
             << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
    solve();
#endif
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值