zoukankan      html  css  js  c++  java
  • bzoj4814: [Cqoi2017]小Q的草稿

    Description

    小Q是个程序员。众所周知,程序员在写程序的时候经常需要草稿纸。小Q现在需要一张草稿纸用来画图,但是桌上
    只有一张草稿纸,而且是一张被用过很多次的草稿纸。草稿纸可以看作一个二维平面,小Q甚至已经给它建立了直
    角坐标系。以前每一次草稿使用过的区域,都可以近似的看作一个平面上的一个三角形,这个三角形区域的内部和
    边界都不能再使用。当然了,以前的草稿也没有出现区域重叠的情况。小Q已经在草稿纸上画上了一些关键点,这
    些关键点都在没使用过的区域。小Q想把这些关键点两两之间尽可能的用线段连接起来。连接两个关键点的线段有
    可能会穿过已经用过的草稿区域,这样显然不允许。于是小Q就想知道,有多少对关键点可以被线段连接起来,而
    且还不会穿过已经用过的区域。为了方便,小Q保证任意三个关键点不会共线。

    Input

    第一行包含两个整数V,T,表示草稿纸上的关键点数量和三角形区域数量。
    接下来V行,每行两个整数x,y,表示一个关键点的坐标(x,y)。
    接下来T行,每行六个整数x1,y1,x2,y2,x3,y3,表示一个三角形区域的三个顶点坐标分别是(x1,y1),(x2,y2),(x3,y
    3)保证三角形的面积大于0。
    V<=1000,T<=1000,0<=所有坐标<=10^8且为整数

    Output

    输出一行,一个整数,表示能够被线段连接起来的关键点有多少对。

    对每个点以它为中心进行扫描线,处理在右方的点和三角形。

    #include<bits/stdc++.h>
    typedef long long i64;
    typedef double ld;
    int n,m;
    int sgn(i64 x){return x<0?-1:x>0;}
    struct pos{
        int x,y;
        void R(){scanf("%d%d",&x,&y);}
        i64 pw2(){return i64(x)*x+i64(y)*y;}
    }ps[1007],ws[1007],trs[1007][3],O=(pos){0,0},now;
    pos operator-(const pos&a,const pos&b){return (pos){a.x-b.x,a.y-b.y};}
    int operator*(const pos&a,const pos&b){return sgn(i64(a.x)*b.y-i64(a.y)*b.x);}
    ld mul(const pos&a,const pos&b){return ld(a.x)*b.y-ld(a.y)*b.x;}
    bool cmp(const pos&a,const pos&b){return a.x!=b.x?a.x<b.x:a.y<b.y;}
    bool operator<(const pos&a,const pos&b){return a*b<0;}
    struct seg{
        pos a[2];
        ld val()const{return mul(a[0],a[1])/mul(now,a[1]-a[0]);}
        bool operator<(const seg&w)const{return val()<w.val();}
    };
    std::set<seg>st;
    std::set<seg>::iterator its[2007];
    struct Q{
        pos a[2];
        int t,id;
        bool operator<(const Q&w)const{
            int x=a[t]*w.a[w.t];
            return x?x<0:t<w.t;
        }
        bool operator<(const pos&w){
            int x=a[t]*w;
            return x?x<0:!t;
        }
        void cal(){
            now=a[t];
            if(cmp(now,O))now=(pos){0,1};
            if(t)st.erase(its[id]);
            else{
                seg s=(seg){a[0],a[1]};
                its[id]=st.insert(s).first;
            }
        }
    }qs[2007];
    bool cross(pos a,pos b1,pos b2){
        pos ba=b2-a;
        if((a*(b1-a))*(a*ba)>0)return 0;
        pos b3=b1-b2;
        return (b3*b2)*(b3*ba)<=0;
    }
    int ans=0,wp,qp,ip;
    void scl(){
        for(int i=0,j=0;i<wp;++i){
            for(;j<qp&&qs[j]<ws[i];qs[j++].cal());
            if(st.empty()||!cross(ws[i],st.begin()->a[0],st.begin()->a[1]))++ans;
        }
    }
    void aq(pos a,pos b){
        bool da=cmp(O,a),db=cmp(O,b);
        ++ip;
        if(da)qs[qp++]=(Q){a,b,0,ip};
        else if(db)((Q){a,b,0,ip}).cal();
        if(db)qs[qp++]=(Q){a,b,1,ip};
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)ps[i].R();
        std::sort(ps+1,ps+n+1,cmp);
        for(int i=1;i<=m;++i)for(int j=0;j<3;++j)trs[i][j].R();
        for(int i=1;i<=n;++i){
            st.clear();
            wp=0,qp=0,ip=0;
            for(int j=i+1;j<=n;++j)ws[wp++]=ps[j]-ps[i];
            std::sort(ws,ws+wp);
            for(int j=1;j<=m;++j){
                pos tr[3];
                for(int t=0;t<3;++t)tr[t]=trs[j][t]-ps[i];
                std::sort(tr,tr+3);
                aq(tr[0],tr[2]);
            }
            std::sort(qs,qs+qp);
            scl();
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    行列式的六条运算法则整理
    李昊大佬的CV模板
    洛谷P2918 [USACO08NOV]买干草(一道完全背包模板题)
    .
    洛谷P2822 组合数问题
    欧拉筛法模板&&P3383 【模板】线性筛素数
    拓展欧几里得算法
    欧几里得算法求最大公约数模板
    P2678 跳石头
    【五一qbxt】test1
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7337264.html
Copyright © 2011-2022 走看看