UVA12296 Pieces and Discs
阿新 • • 發佈:2018-12-26
題意
分析
可以看成直線切割多邊形,直接維護。
對每個多邊形考慮每條邊和每個點即可。
時間複雜度?不過\(n,m \leq 20\)這種資料怎麼都過了。
程式碼
注意初始化的時候的那個初始長方形的點必須按逆時針順序來插入。
我寫反了,導致調了一晚上。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<algorithm> #include<bitset> #include<cassert> #include<ctime> #include<cstring> #define rg register #define il inline #define co const template<class T>il T read() { rg T data=0; rg int w=1; rg char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) { data=data*10+ch-'0'; ch=getchar(); } return data*w; } template<class T>T read(T&x) { return x=read<T>(); } using namespace std; typedef long long ll; co double eps=1e-8; int dcmp(double x) { return fabs(x)<eps?0:(x<0?-1:1); } struct Point { double x,y; Point(double x=0,double y=0) :x(x),y(y){}; }; typedef Point Vector; typedef vector<Point> Polygon; Vector operator+(co Vector&A,co Vector&B) { return Vector(A.x+B.x,A.y+B.y); } Vector operator-(co Vector&A,co Vector&B) { return Vector(A.x-B.x,A.y-B.y); } Vector operator*(co Vector&A,double p) { return Vector(A.x*p,A.y*p); } double Dot(co Vector&A,co Vector&B) { return A.x*B.x+A.y*B.y; } double Cross(co Vector&A,co Vector&B) { return A.x*B.y-A.y*B.x; } double Length2(co Vector&A) { return Dot(A,A); } Point LineLineIntersection(co Point&P,co Vector&v,co Point&Q,co Vector&w) { Vector u=P-Q; double t=Cross(w,u)/Cross(v,w); return P+v*t; } bool OnSegment(co Point&p,co Point&a1,co Point&a2) { return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0; } double PolygonArea(co Polygon&poly) { double area=0; int n=poly.size(); for(int i=1;i<n-1;++i) area+=Cross(poly[i]-poly[0],poly[(i+1)%n]-poly[0]); return area/2; } Polygon CutPolygon(co Polygon&poly,co Point&A,co Point&B) { Polygon newpoly; int n=poly.size(); for(int i=0;i<n;++i) { co Point&C=poly[i]; co Point&D=poly[(i+1)%n]; if(dcmp(Cross(B-A,C-A))>=0) newpoly.push_back(C); if(dcmp(Cross(B-A,C-D))!=0) { Point ip=LineLineIntersection(A,B-A,C,D-C); if(OnSegment(ip,C,D)) newpoly.push_back(ip); } } return newpoly; } int PointInPolygon(co Point&p,co Polygon&v) { int wn=0; int n=v.size(); for(int i=0;i<n;++i) { if(OnSegment(p,v[i],v[(i+1)%n])) return -1; int k=dcmp(Cross(v[(i+1)%n]-v[i],p-v[i])); int d1=dcmp(v[i].y-p.y); int d2=dcmp(v[(i+1)%n].y-p.y); if(k>0&&d1<=0&&d2>0) ++wn; if(k<0&&d2<=0&&d1>0) --wn; } if(wn!=0) return 1; return 0; } bool InCircle(co Point&p,co Point¢er,double R) { return dcmp(Length2(p-center)-R*R)<0; } int LineCircleIntersection(co Point&A,co Point&B,co Point&C,double r,double&t1,double&t2) { double a=B.x-A.x, b=A.x-C.x, c=B.y-A.y, d=A.y-C.y; double e=a*a+c*c, f=2*(a*b+c*d), g=b*b+d*d-r*r, delta=f*f-4*e*g; if(dcmp(delta)<0) return 0; if(dcmp(delta)==0) { t1=t2=-f/(2*e); return 1; } t1=(-f-sqrt(delta))/(2*e); t2=(-f+sqrt(delta))/(2*e); return 2; } bool CircleIntersectSegment(co Point&A,co Point&B,co Point&p,double R) { double t1,t2; int c=LineCircleIntersection(A,B,p,R,t1,t2); if(c<=1) return 0; if(dcmp(t1)>0&&dcmp(t1-1)<0) return 1; if(dcmp(t2)>0&&dcmp(t2-1)<0) return 1; return 0; } vector<Polygon> pieces,new_pieces; void Cut(int x1,int y1,int x2,int y2) { new_pieces.clear(); for(int i=0;i<pieces.size();++i) { Polygon left=CutPolygon(pieces[i],Point(x1,y1),Point(x2,y2)); Polygon right=CutPolygon(pieces[i],Point(x2,y2),Point(x1,y1)); if(left.size()>=3) new_pieces.push_back(left); if(right.size()>=3) new_pieces.push_back(right); // cerr<<"left="<<endl; // for(int j=0;j<left.size();++j) // cerr<<" "<<left[j].x<<","<<left[j].y; // cerr<<endl; // cerr<<"right="<<endl; // for(int j=0;j<right.size();++j) // cerr<<" "<<right[j].x<<","<<right[j].y; // cerr<<endl; } pieces=new_pieces; } bool DiscIntersectPolygon(co Polygon&poly,co Point&p,double R) { if(PointInPolygon(p,poly)!=0) return 1; if(InCircle(poly[0],p,R)) return 1; int n=poly.size(); for(int i=0;i<n;++i) { if(CircleIntersectSegment(poly[i],poly[(i+1)%n],p,R)) return 1; if(InCircle((poly[i]+poly[(i+1)%n])*0.5,p,R)) return 1; } return 0; } void Query(co Point&p,int R) { vector<double>ans; for(int i=0;i<pieces.size();++i) if(DiscIntersectPolygon(pieces[i],p,R)) ans.push_back(fabs(PolygonArea(pieces[i]))); printf("%d",ans.size()); sort(ans.begin(),ans.end()); for(int i=0;i<ans.size();++i) printf(" %.2lf",ans[i]); printf("\n"); } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); int n,m,L,W; while(read(n)|read(m)|read(L)|read(W)) { // cerr<<"n="<<n<<" m="<<m<<" L="<<L<<" W="<<W<<endl; pieces.clear(); Polygon bbox; bbox.push_back(Point(0,0)); // edit 1:must follow the order bbox.push_back(Point(L,0)); bbox.push_back(Point(L,W)); bbox.push_back(Point(0,W)); pieces.push_back(bbox); for(int i=0;i<n;++i) { int x1,y1,x2,y2; read(x1),read(y1),read(x2),read(y2); // cerr<<"x1="<<x1<<" y1="<<y1<<" x2="<<x2<<" y2="<<y2<<endl; Cut(x1,y1,x2,y2); // for(int i=0;i<pieces.size();++i) // { // cerr<<i<<" poly="<<endl; // for(int j=0;j<pieces[i].size();++j) // cerr<<" "<<pieces[i][j].x<<","<<pieces[i][j].y; // cerr<<endl; // } } for(int i=0;i<m;++i) { int x,y,R; read(x),read(y),read(R); Query(Point(x,y),R); } printf("\n"); } return 0; }