[几何 扫描线] LOJ#6260. 「CodePlus 2017 12 月赛」寄蒜几盒
2018-02-06 13:33
645 查看
直线很少,把交点算出来扫描线
多边形的数量是 O(n2)O(n2) 的,因为是平面图,所以顶点的总数也是 O(n2)O(n2) 的,搞一搞就好了
多边形的数量是 O(n2)O(n2) 的,因为是平面图,所以顶点的总数也是 O(n2)O(n2) 的,搞一搞就好了
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <vector> #define eq(a,b) (fabs(a-b)<eps) #define IN(x) ((x)>=-L && (x)<=L) #define pb push_back using namespace std; typedef double ld; const int N=510,M=1000010; const ld eps=1e-7; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline void read(int &x){ char c=nc(); x=0; for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); } inline void read(ld &x){ char c=nc(); int f=1,flg=0,dv=1; x=0; for(;c>'9'||c<'0';c=nc())if(c=='-')f=-1; for(;c>='0'&&c<='9' || c=='.';x=x*10+c-'0',c=nc(),dv=flg?dv*10:dv) if(c=='.'){ flg=1; c=nc(); } x/=dv; x*=f; } ld L,l,r; int cnt,tot,t,n,m,id ; ld A ,B ,C ; struct Point{ ld x,y; Point(ld _x=0,ld _y=0):x(_x),y(_y){} friend bool operator <(const Point &a,const Point &b){ if(a==b) return 0; if(!eq(a.x,b.x)) return a.x<b.x; return a.y<b.y; } friend bool operator ==(const Point &a,const Point &b){ return eq(a.x,b.x) && eq(a.y,b.y); } }; struct node{ Point x; int g,a,b; friend bool operator <(const node &a,const node &b){ if(a.x==b.x) return a.a<b.a; return a.x<b.x; } }a[M]; vector<ld> border; vector<Point> polygon[M]; inline Point Cross(int x,int y){ ld k1=-A[x]/B[x],d1=-C[x]/B[x],k2=-A[y]/B[y],d2=-C[y]/B[y]; if(eq(k1,k2)) return Point(-1e20,-1e20); Point ret; ret.x=(d1-d2)/(k2-k1); ret.y=k1*ret.x+d1; return ret; } int ans[M]; inline ld f(int g,ld x){ return -(A[g]*x+C[g])/B[g]; } inline bool cmp(const int &a,const int &b){ if(!eq(f(a,l),f(b,l))) return f(a,l)<f(b,l); return -A[a]/B[a]>-A[b]/B[b]; } int p=1,rk ,pnum ; inline void work(){ for(int i=1;i<t;i++){ ++cnt; polygon[cnt].pb(Point(l,f(id[i],l))); polygon[cnt].pb(Point(l,f(id[i+1],l))); pnum[i]=cnt; } for(;p<=tot;p++){ if(a[p].x.x>r) break; if(a[p].g){ int l=1,r=t,res,mid; while(l<=r) f(id[mid=l+r>>1],a[p].x.x)<a[p].x.y?l=(res=mid)+1:r=mid-1; ans[a[p].g]=pnum[res]; continue; } int np=p,revL=min(rk[a[p].a],rk[a[p].b]),revR=max(rk[a[p].a],rk[a[p].b]); while(np<tot && a[np+1].x==a[p].x){ np++; revL=min(min(rk[a[np].a],rk[a[np].b]),revL); revR=max(max(rk[a[np].a],rk[a[np].b]),revR); } if(pnum[revL-1]) polygon[pnum[revL-1]].pb(a[p].x); if(pnum[revR]) polygon[pnum[revR]].pb(a[p].x); reverse(id+revL,id+revR+1); for(int i=revL;i<=revR;i++){ rk[id[i]]=i; if(i==revR) break; polygon[pnum[i]].pb(a[p].x); pnum[i]=++cnt; polygon[cnt].pb(a[p].x); } p=np; } for(int i=1;i<t;i++){ polygon[pnum[i]].pb(Point(r,f(id[i],r))); polygon[pnum[i]].pb(Point(r,f(id[i+1],r))); } } ld size[M]; int vis[M]; Point s; inline bool cmp1(const Point &a,const Point &b){ return (a.y-s.y)*(b.x-s.x)<(b.y-s.y)*(a.x-s.x); } inline ld cross(const Point &a,const Point &b){ return (a.x-s.x)*(b.y-s.y)-(a.y-s.y)*(b.x-s.x); } inline ld calc(int x){ vector<Point> &c=polygon[x]; for(int i=1;i<c.size();i++) if(c[i]<c[0]) swap(c[i],c[0]); s=c[0]; sort(c.begin()+1,c.end(),cmp1); ld ret=0; for(int i=1;i<c.size()-1;i++) ret+=cross(c[i],c[i+1]); return ret/2; } void PutAns(int x){ if(x>=10) PutAns(x/10); putchar(x%10+'0'); } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(m); read(L); for(int i=1;i<=n;i++){ read(A[i]); read(B[i]); read(C[i]); if(!eq(B[i],0)) id[++t]=i; else if(IN(C[i]/A[i])) border.pb(-C[i]/A[i]); } id[++t]=n+1; A[n+1]=0; B[n+1]=1; C[n+1]=L; id[++t]=n+2; A[n+2]=0; B[n+2]=1; C[n+2]=-L; border.pb(-L); border.pb(L); sort(border.begin(),border.end()); l=-L; sort(id+1,id+1+t,cmp); for(int i=1;i<=t;i++) rk[id[i]]=i; for(int i=1;i<=t;i++) for(int j=i+1;j<=t;j++){ Point cur=Cross(id[i],id[j]); //printf("%d %d %.2lf %.2lf\n",i,j,cur.x,cur.y); if(!IN(cur.x)) continue; ++tot; a[tot].x=cur; a[tot].a=id[i]; a[tot].b=id[j]; a[tot].g=0; } for(int i=1;i<=m;i++){ ++tot; read(a[tot].x.x); read(a[tot].x.y); a[tot].g=i; } sort(a+1,a+1+tot); for(int i=0;i<border.size()-1;i++){ l=border[i]; r=border[i+1]; if(eq(l,r)) continue; work(); } /*for(int i=1;i<=cnt;i++){ printf("%d : ",i); for(auto x : polygon[i]) printf("%.2lf %.2lf\n",x.x,x.y); putchar('\n'); }*/ for(int i=1;i<=m;i++){ if(!vis[ans[i]]) vis[ans[i]]=1,size[ans[i]]=calc(ans[i]); PutAns((int)(size[ans[i]]+0.005)); putchar('.'); int r=(long long)(size[ans[i]]*100+0.5)%100; if(r<10) putchar('0'); PutAns(r); putchar('\n'); //printf("%.2lf\n",size[ans[i]]); } return 0; }
相关文章推荐
- LOJ #6256. 「CodePlus 2017 12 月赛」可做题1
- [LOJ6259][CodePlus 2017 12 月赛]白金元首与独舞-矩阵树定理
- CodePlus 2017 12 月赛 可做题2 矩阵乘法+exgcd
- 【LibreOJ】#6257. 「CodePlus 2017 12 月赛」可做题2
- [几何 扫描线 最大子段和] JOI Open Contest 2017 Bulldozer
- [矩阵树定理] LOJ#6259. 「CodePlus 2017 12 月赛」白金元首与独舞
- 洛谷 P4032 「CodePlus 2017 12 月赛」火锅盛宴(splay+堆)
- 【BZOJ5136】【LOJ6256】【CodePlus 2017 12 月赛】可做题1 & LibreOJ6256
- 走进矩阵树定理--「CodePlus 2017 12 月赛」白金元首与独舞
- 【CodePlus 2017 12 月赛】白金元首与独舞
- 【LIbreOJ】#6256. 「CodePlus 2017 12 月赛」可做题1
- 【loj6257】「CodePlus 2017 12 月赛」可做题2
- CodePlus 2017 12 月赛 白金元首与独舞 矩阵树定理求有向图生成树数量
- 「CodePlus 2017 12 月赛」可做题2(矩阵快速幂+exgcd+二分)
- 「CodePlus 2017 12 月赛」火锅盛宴
- 「CodePlus 2017 12 月赛」白金元首与独舞
- 「CodePlus 2017 12 月赛」火锅盛宴(模拟+树状数组)
- 【LibreOJ】#6259. 「CodePlus 2017 12 月赛」白金元首与独舞
- 「CodePlus 2017 11 月赛」Yazid 的新生舞会
- [从头学数学] 第265节 [计算几何] 多线段求交点(扫描线法)