bzoj 4814 [Cqoi2017]小Q的草稿

以每个点为中心,极角排序,扫描线,用set维护当前极角下的线段集合,因为三角形不相交,所以set里面线段的相对顺序不会变。当扫到一个点的时候,看set里面离原点最近的线段会不会挡住当前点。
TLE卡了很久,发现point构造函数里面不要获取极角,因为三角函数atan2很慢。在有需要的时候再获取
还有一个小技巧是三角形的三条边实际上只有一条有用,因为点不会在三角形内部。
另外,下午在做另外一个题的时候,卡了atan2极角排序,坐标范围在1e9,所以可以构造数据卡极角排序(long double也没有用)。因为在第一象限,用叉积排序就好。以后可以用叉积排序就用叉积排,三角函数好慢啊!!!
留个东西

#include 

using namespace std;

#define LL long long
#define pii pair
#define MP make_pair
#define ls i << 1
#define rs ls | 1
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define mod 1000000007
#define inf 0x3f3f3f3f
#define Pi acos(-1.0)
#define eps 1e-12
#define N 6020
#define M 400020

char buf[12000000],*pt = buf,*o = buf;
int getint(){
    int f = 1,x = 0;
    while((*pt != '-') && (*pt < '0' || *pt > '9'))    pt ++;
    if(*pt == '-')    f = -1,pt ++;    else    x = *pt++ - 48;
    while(*pt >= '0' && *pt <= '9')    x = x * 10 + *pt ++ - 48;
    return x * f;
}
char getch(){
    char ch;
    while(*pt < 'A' || *pt > 'Z')    pt ++;
    ch=*pt;pt++;
    return ch;
}
int dcmp(double x){
    if(fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}
int sgn(LL x){
    if(x == 0) return 0;
    return x < 0 ? -1 : 1;
}
struct point{
    double x, y, ang;
    point(double x = 0, double y = 0) : x(x), y(y) {}
    point operator - (const point &b) const {
        return point(x - b.x, y - b.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);
    }
    bool operator < (const point &b) const {
        return ang < b.ang;
    }
    bool operator == (const point &b) const {
        return x == b.x && y == b.y;
    }
    double len(){
        return sqrt(x * x + y * y);
    }
    void get_ang(){
        ang = atan2(y, x);
    }
    void input(){
        int xx, yy;
        scanf("%d%d", &xx, &yy);
        x = 1.0 * xx, y = 1.0 * yy;
    }
};
double dot(point a, point b){
    return a.x * b.x + a.y * b.y;
}
double cross(point a, point b){
    return a.x * b.y - a.y * b.x;
}
point get_intersection(point a1, point a2, point b1, point b2){
    point u = a1 - b1, av = a2 - a1, bv = b2 - b1;
    double t = cross(bv, u) / cross(av, bv);
    return a1 + av * t;
}
const point O = point(0, 0);
point base;
struct Seg{
    point u, v;
    int id, in;
    double ang;
    Seg(){}
    Seg(point u, point v, int in, int id, double ang) : u(u), v(v), in(in), id(id), ang(ang) {}
    bool operator < (const Seg &b) const {
        if(u == b.u){
            return cross(v - u, b.v - u) < 0;
        }
        point aa = get_intersection(u, v, O, base);
        point bb = get_intersection(b.u, b.v, O, base);
        return aa.len() < bb.len();
    }
}L[N];
bool cmp(Seg a, Seg b){
    return dcmp(a.ang - b.ang) < 0 || dcmp(a.ang - b.ang) == 0 && a.in > b.in;
}

int all, tot;
multiset S;
multiset::iterator it[N];
point pp[N], p[N];
point tri[N][3], t[N][3];
void add(point u, point v, int id){
    if(u.ang > v.ang) swap(u, v);
    L[all++] = Seg(u, v, 1, id, u.ang);
    L[all++] = Seg(v, u, 0, id, v.ang);
}
double calc(Seg s){
    point a = get_intersection(s.u, s.v, O, base);
    return a.len();
}
int solve(int n){
    sort(p, p + n);
    sort(L, L + all, cmp);
    S.clear();
    int ret = 0, i = 0, j = 0;
    for(; i < n; ++i){
        while(j < all && (dcmp(L[j].ang - p[i].ang) < 0 || (dcmp(L[j].ang - p[i].ang) == 0 && L[j].in))){
            base = L[j].u;
            if(L[j].in)
                it[L[j].id] = S.insert(L[j]);
            else
                S.erase(it[L[j].id]);
            ++j;
        }
        if(S.empty()){
            ++ret; continue;
        }
        base = p[i];
        double dis = calc(*S.begin());
        if(dcmp(p[i].len() - dis) <= 0) ++ret;
    }
//  printf("size %d\n", S.size());
    return ret;
}

int main(){
    //fread(buf, 1, 12000000, stdin);
    int V, T;
    scanf("%d%d", &V, &T);
        for(int i = 1; i <= V; ++i)
            pp[i].input();
        for(int i = 1; i <= T; ++i)
            for(int j = 0; j < 3; ++j)
                tri[i][j].input();

        int ans = 0;
        for(int i = 1; i <= V; ++i){
            int cnt = 0;
            for(int j = i + 1; j <= V; ++j){
                p[cnt++] = pp[j] - pp[i];
                p[cnt-1].get_ang();
            }
            tot = all = 0;
            for(int j = 1; j <= T; ++j){
                for(int k = 0; k < 3; ++k)
                    t[j][k] = tri[j][k] - pp[i];
                t[j][3] = t[j][0];
                point u, v;
                double mx = 0;
                for(int k = 0; k < 3; ++k){
                    double ang = dot(t[j][k], t[j][k+1]) / t[j][k].len() / t[j][k+1].len();
                    ang = acos(ang);
                    if(ang > mx)
                        mx = ang, u = t[j][k], v = t[j][k+1];
                }
                u.get_ang(), v.get_ang();
                double d = fabs(u.ang - v.ang);
                if(d < Pi)
                    add(u, v, tot++);
                else{
                    point tmp = get_intersection(u, v, O, point(-1.0, 0));
                    tmp.ang = Pi * dcmp(u.ang);
                    add(u, tmp, tot++);
                    tmp.ang = Pi * dcmp(v.ang);
                    add(v, tmp, tot++);
                }
            }
            int ret = solve(cnt);
        //  printf("%.2f %.2f %d\n", pp[i].x, pp[i].y, ret);
            ans += ret;
        }
        printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(扫描线,acm模板)