[CQOI2005]三角形面積並

題面

題意

給出n個三角形,求它們的面積並。

做法

首先求出所有點的座標(包括三角形的頂點座標和三角形邊的所有交點),根據它們的橫座標分段之後可以發現每一部分的面積都等價於梯形,然後暴力求出這幾個橫座標上的線段長度和,再逐塊相加即可。

代碼

#include<bits/stdc++.h>
#define db double
#define P pair<db,db>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define eps 1e-8
#define INF 0x3f3f3f3f
#define N 110
#define M 100100
using namespace std;

int n,nn,xx;
db ans,zj=666;
bool deb;
struct Node
{
    db x,y;
    void in()
    {
    db p,q;
    scanf("%lf%lf",&p,&q);
    x=cos(zj)*p-sin(zj)*q;
    y=cos(zj)*q+sin(zj)*p;
    }
    Node operator + (const Node &u) const{return (Node){x+u.x,y+u.y};}
    Node operator - (const Node &u) const{return (Node){x-u.x,y-u.y};}
    Node operator * (const db &u) const{return (Node){x*u,y*u};}
    Node operator / (const db &u) const{return (Node){x/u,y/u};}
    bool operator < (const Node u){return x<u.x;}
}node[M];
struct Xn
{
    Node a,v;
    void make(Node p,Node q){a=p,v=q-p;}
}xn[N*3];
struct Sj
{
    Node a,b,c;
}sj[N];
vector<P>use;

inline db cj(Node u,Node v){return u.x*v.y-u.y*v.x;}
inline bool up(Node u,Xn v){return cj(v.a-u,v.a+v.v-u)>0;}
inline bool bet(db u,Xn v)
{
    if(fabs(v.v.x)<eps) return 0;
    return u+eps>min(v.a.x,(v.a+v.v).x) && u<max(v.a.x,(v.a+v.v).x)+eps;
}
inline db xd(db u,Xn v)
{
    if(deb) cout<<"   "<<(v.a+v.v*(u-v.a.x)/v.v.x).y<<endl;
    return (v.a+v.v*(u-v.a.x)/v.v.x).y;
}
inline bool yj(Xn u,Xn v)
{
    if(fabs(cj(v.v,u.v))<eps) return 0;
    return (up(u.a,v)^up(u.a+u.v,v)) && (up(v.a,u)^up(v.a+v.v,u));
}
inline Node jd(Xn u,Xn v)
{
    db t=(cj(u.a,u.v)-cj(v.a,u.v))/cj(v.v,u.v);
    return v.v*t+v.a;
}

inline db ask(db u)
{
    int i,j;
    db res=0,t,r;
    P tmp;
    Xn a,b,c;
    use.clear();
    for(i=1;i<=n;i++)
    {
    a.make(sj[i].a,sj[i].b);
    b.make(sj[i].a,sj[i].c);
    c.make(sj[i].b,sj[i].c);
    if(bet(u,a)+bet(u,b)+bet(u,c)<2) continue;
    tmp.fi=INF,tmp.se=-INF;
    if(bet(u,a)) t=xd(u,a),tmp.fi=min(tmp.fi,t),tmp.se=max(tmp.se,t);
    if(bet(u,b)) t=xd(u,b),tmp.fi=min(tmp.fi,t),tmp.se=max(tmp.se,t);
    if(bet(u,c)) t=xd(u,c),tmp.fi=min(tmp.fi,t),tmp.se=max(tmp.se,t);
    use.pb(tmp);
    }
    sort(use.begin(),use.end());
    for(i=0;i<use.size();i=j)
    {
    r=use[i].se;
    for(j=i+1;j<use.size();j++)
    {
        if(use[j].fi>r) break;
        r=max(r,use[j].se);
    }
    res+=r-use[i].fi;
    }
    return res;
}

int main()
{
    int i,j;
    db p,q;
    cin>>n;
    for(i=1;i<=n;i++)
    {
    sj[i].a.in();
    sj[i].b.in();
    sj[i].c.in();
    xn[++xx].make(sj[i].a,sj[i].b);
    xn[++xx].make(sj[i].a,sj[i].c);
    xn[++xx].make(sj[i].b,sj[i].c);
    node[++nn]=sj[i].a;
    node[++nn]=sj[i].b;
    node[++nn]=sj[i].c;
    }
    for(i=1;i<=xx;i++)
    {
    for(j=i+1;j<=xx;j++)
    {
        if(!yj(xn[i],xn[j])) continue;
        node[++nn]=jd(xn[i],xn[j]);
    }
    }
    sort(node+1,node+nn+1);
    p=ask(node[1].x);
    for(i=1;;i=j)
    {
    for(j=i+1;j<=nn;j++) if(node[j].x-node[i].x>eps) break;
    if(j>nn) break;
    q=ask(node[j].x);
    ans+=(p+q)*(node[j].x-node[i].x)/2.0;
    p=q;
    }
    printf("%.2f",ans-eps);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章