NOI十连测 第六测 T3
思路:考试的时候我非常地**,写了圆并,然后还TM写了半平面交和三角剖分,虽然只有30分。。但是看在我写了500行的份上还是挂着吧。。
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 const double Pi=acos(-1); 7 const double eps=1e-10; 8 int n,m,cnt,tot,num; 9 bool pd[200005],check; 10 int read(){ 11 int t=0,f=1;char ch=getchar(); 12 while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} 13 while ('0'<=ch&&ch<='9') {t=t*10+ch-'0';ch=getchar();} 14 return t*f; 15 } 16 struct node{ 17 double l,r; 18 }L[200005]; 19 struct Point{ 20 double x,y; 21 Point(){} 22 Point(double x0,double y0):x(x0),y(y0){} 23 }p[200005],c[200005],d[200005]; 24 struct Line{ 25 Point s,e; 26 double slop; 27 Line(){} 28 Line(Point s0,Point e0):s(s0),e(e0){} 29 }l[200005],q[200005]; 30 struct Circle{ 31 Point p; 32 double r; 33 Circle(){} 34 Circle(double x0,double y0,double r0):p(Point(x0,y0)),r(r0){} 35 }a[200005]; 36 bool cmp2(node a,node b){ 37 if (fabs(a.l-b.l)<eps) return a.r<b.r; 38 else return (a.l<b.l); 39 } 40 int sgn(double x){if (x>eps) return 1;if (x<-eps) return -1;return 0;} 41 double operator *(Point p1,Point p2){return p1.x*p2.y-p1.y*p2.x;} 42 double operator /(Point p1,Point p2){return p1.x*p2.x+p1.y*p2.y;} 43 Point operator -(Point p1,Point p2){return Point(p1.x-p2.x,p1.y-p2.y);} 44 Point operator +(Point p1,Point p2){return Point(p1.x+p2.x,p1.y+p2.y);} 45 Point operator *(Point p1,double x){return Point(p1.x*x,p1.y*x);} 46 Point operator /(Point p1,double x){return Point(p1.x/x,p1.y/x);} 47 double sqr(double x){return x*x;} 48 double llen(Point p1){return sqrt(sqr(p1.x)+sqr(p1.y)); } 49 double dis(Point p1,Point p2){return llen(p1-p2);} 50 double dis(Point p1){return llen(p1);} 51 Point evector(Point p1){double t=llen(p1);if (t<eps) return Point(0,0);else return p1/t;} 52 bool cmp3(Line p1,Line p2){ 53 if (p1.slop!=p2.slop) return p1.slop<p2.slop; 54 else return (p1.e-p1.s)*(p2.e-p1.s)>0; 55 } 56 bool cmp(Point p1,Point p2){ 57 double t=(p1-p[1])*(p2-p[1]); 58 if (fabs(t)<eps) return dis(p[1],p1)<dis(p[1],p2); 59 return t>0; 60 } 61 bool conclude(Circle p1,Circle p2){ 62 double Len=dis(p1.p,p2.p); 63 if (fabs(p1.r-p2.r)>=Len) return 1; 64 return 0; 65 } 66 bool intersect(Circle p1,Circle p2){ 67 double Len=dis(p1.p,p2.p); 68 if (fabs(p1.r-p2.r)<=Len&&Len<=p1.r+p2.r) return 1; 69 return 0; 70 } 71 double dist_line(Line p){ 72 double A,B,C,dist; 73 A=p.s.y-p.e.y; 74 B=p.s.x-p.e.x; 75 C=p.s.x*p.e.y-p.s.y*p.e.x; 76 dist=fabs(C)/sqrt(sqr(A)+sqr(B)); 77 return dist; 78 } 79 double dist_line(Point p1,Line p){ 80 p.s.x-=p1.x; 81 p.e.x-=p1.x; 82 p.s.y-=p1.y; 83 p.e.y-=p1.y; 84 return dist_line(p); 85 } 86 double get_cos(double a,double b,double c){ 87 return (b*b+c*c-a*a)/(2*b*c); 88 } 89 double get_angle(Point p1,Point p2){ 90 if (!sgn(dis(p1))||!sgn(dis(p2))) return 0.0; 91 double A,B,C; 92 A=dis(p1); 93 B=dis(p2); 94 C=dis(p1,p2); 95 if (C<=eps) return 0.0; 96 return fabs(acos(get_cos(C,A,B))); 97 } 98 Point get_point(Point p){ 99 double T=sqr(p.x)+sqr(p.y); 100 return Point(sgn(p.x)*sqrt(sqr(p.x)/T),sgn(p.y)*sqrt(sqr(p.y)/T)); 101 } 102 bool bigconclude(Circle p1,Circle p2,Point p){ 103 Point e1=p2.p-p1.p; 104 Point e2=p-p1.p; 105 if (sgn(e1/e2)<0) return 1; 106 else return 0; 107 } 108 double S(Point p1,Point p2,Point p3){ 109 return fabs((p2-p1)*(p3-p1))/2; 110 } 111 double work(Point p1,Point p2,double R){ 112 Point O=Point(0,0); 113 double f=sgn(p1*p2),res=0; 114 if (!sgn(f)||!sgn(dis(p1))||!sgn(dis(p2))) return 0.0; 115 double l=dist_line(Line(p1,p2)); 116 double a=dis(p1); 117 double b=dis(p2); 118 double c=dis(p1,p2); 119 if (a<=R&&b<=R){ 120 return fabs(p1*p2)/2.0*f; 121 } 122 if (a>=R&&b>=R&&l>=R){ 123 double ang=get_angle(p1,p2); 124 return fabs((ang/(2.0))*(R*R))*f; 125 } 126 if (a>=R&&b>=R&&l<=R&&(get_cos(a,b,c)<=0||get_cos(b,a,c)<=0)){ 127 double ang=get_angle(p1,p2); 128 return fabs((ang/(2.0))*(R*R))*f; 129 } 130 if (a>=R&&b>=R&&l<=R&&(get_cos(a,b,c)>0&&get_cos(b,a,c)>0)){ 131 double dist=dist_line(Line(p1,p2)); 132 double len=sqrt(sqr(R)-sqr(dist))*2.0; 133 double ang1=get_angle(p1,p2); 134 double cos2=get_cos(len,R,R); 135 res+=fabs(len*dist/2.0); 136 double ang2=ang1-acos(cos2); 137 res+=fabs((ang2/(2))*(R*R)); 138 return res*f; 139 } 140 if ((a>=R&&b<R)||(a<R&&b>=R)){ 141 if (b>a) std::swap(a,b),std::swap(p1,p2); 142 double T=sqr(p1.x-p2.x)+sqr(p1.y-p2.y); 143 Point u=Point(sgn(p1.x-p2.x)*sqrt(sqr(p1.x-p2.x)/T),sgn(p1.y-p2.y)*sqrt(sqr(p1.y-p2.y)/T)); 144 double dist=dist_line(Line(p1,p2)); 145 double len=sqrt(R*R-dist*dist); 146 double len2=sqrt(sqr(dis(p2))-sqr(dist)); 147 if (fabs(dis(p2+u*len2)-dist)<=eps) len+=len2; 148 else len-=len2; 149 Point p=p2+u*len; 150 res+=S(O,p2,p); 151 double ang=get_angle(p1,p); 152 res+=fabs((ang/2.0)*R*R); 153 return res*f; 154 } 155 return 0; 156 } 157 Point inter(Line p1,Line p2){ 158 double t1=(p2.e-p1.s)*(p1.e-p1.s); 159 double t2=(p1.e-p1.s)*(p2.s-p1.s); 160 if (fabs(t1+t2)<eps) check=1; 161 double k=t1/(t1+t2); 162 Point p; 163 p.x=p2.e.x+(p2.s.x-p2.e.x)*k; 164 p.y=p2.e.y+(p2.s.y-p2.e.y)*k; 165 return p; 166 } 167 bool jud(Line p1,Line p2,Line p3){ 168 Point p=inter(p1,p2); 169 return (p3.e-p3.s)*(p-p3.s)<0; 170 } 171 double inter(Circle P){ 172 double res=0;p[n+1]=p[1]; 173 for (int i=1;i<=n+1;i++) 174 c[i].x=p[i].x-P.p.x,c[i].y=p[i].y-P.p.y; 175 for (int i=1;i<=n;i++) 176 res+=work(c[i],c[i+1],P.r); 177 return res; 178 } 179 void hpi(){ 180 int L=1,R=0;tot=0; 181 for (int i=1;i<=cnt;i++){ 182 if (l[i].slop!=l[i-1].slop) tot++; 183 l[tot]=l[i]; 184 } 185 q[++R]=l[1];q[++R]=l[2]; 186 int all=tot; 187 for (int i=3;i<=all;i++){ 188 while (L<R&&jud(q[R],q[R-1],l[i])) R--; 189 while (L<R&&jud(q[L],q[L+1],l[i])) L++; 190 q[++R]=l[i]; 191 } 192 while (L<R&&jud(q[R],q[R-1],q[L])) R--; 193 while (L<R&&jud(q[L],q[L+1],q[R])) L++; 194 tot=0; 195 for (int i=L;i<R;i++) 196 d[++tot]=inter(q[i],q[i+1]); 197 } 198 bool judge(Point p1,Point p2){ 199 return (fabs(p1.x-p2.x)<eps&&fabs(p1.y-p2.y)<eps); 200 } 201 double gworking1(Point c1,Point c2,Point p1,Point p2){ 202 double rev=sgn(c1*c2); 203 if (fabs(rev)<eps) return 0; 204 num=0; 205 Point O=Point(0,0); 206 if ((c1*c2)<0) std::swap(c1,c2); 207 l[++num].s=O,l[num].e=c1;if (judge(l[num].s,l[num].e)) num--; 208 l[++num].s=c1,l[num].e=c2;if (judge(l[num].s,l[num].e)) num--; 209 l[++num].s=c2,l[num].e=O;if (judge(l[num].s,l[num].e)) num--; 210 if ((p1*p2)<0) std::swap(p1,p2); 211 l[++num].s=O,l[num].e=p1;if (judge(l[num].s,l[num].e)) num--; 212 l[++num].s=p1,l[num].e=p2;if (judge(l[num].s,l[num].e)) num--; 213 l[++num].s=p2,l[num].e=O;if (judge(l[num].s,l[num].e)) num--; 214 for (int i=1;i<=num;i++) 215 l[i].slop=atan2(l[i].e.y-l[i].s.y,l[i].e.x-l[i].s.x); 216 std::sort(l+1,l+1+num,cmp3); 217 check=0; 218 hpi(); 219 if (check) return 0; 220 d[tot+1]=d[1]; 221 double res=0; 222 for (int i=1;i<=tot;i++) 223 res+=(d[i]*d[i+1])/2.0; 224 return fabs(res)*rev; 225 } 226 double Gworking1(double a1,double a2,Circle w){ 227 double r=w.r; 228 Point p1=Point(r*cos(a1),r*sin(a1)); 229 Point p2=Point(r*cos(a2),r*sin(a2)); 230 p[n+1]=p[1]; 231 for (int i=1;i<=n+1;i++) 232 c[i]=Point(p[i].x-w.p.x,p[i].y-w.p.y); 233 double res=0; 234 for (int i=1;i<=n;i++) 235 res+=gworking1(c[i],c[i+1],p1,p2); 236 return res; 237 } 238 Point inter(Circle p,Line l,Point p1){ 239 double Dist=dist_line(l); 240 double dis1=llen(p1); 241 double len=sqrt(sqr(dis1)-sqr(Dist)); 242 Point e=evector(l.e-l.s); 243 Point sx=p1; 244 double R=p.r; 245 double len2=sqrt(sqr(R)-sqr(Dist)); 246 sx=sx-e*len; 247 sx=sx+e*len2; 248 return sx; 249 } 250 double gworking2(Point c1,Point c2,Point p1,Point p2,double R){ 251 double rev=sgn(c1*c2),res=0;Point O=Point(0,0); 252 if ((p1*p2)<0) std::swap(p1,p2); 253 if ((c1*c2)<0) std::swap(c1,c2); 254 if (fabs(rev)<eps) return 0; 255 if (!sgn(dis(p1))||!sgn(dis(p2))) return 0.0; 256 double l=dist_line(Line(p1,p2)); 257 double a=dis(p1); 258 double b=dis(p2); 259 double c=dis(p1,p2); 260 if (a<=R&&b<=R){ 261 res=fabs(p1*p2)/2.0; 262 } 263 else 264 if (a>=R&&b>=R&&l>=R){ 265 double ang=get_angle(p1,p2); 266 res=abs((ang/(2.0))*(R*R)); 267 } 268 else 269 if (a>=R&&b>=R&&l<=R&&(get_cos(a,b,c)<=0||get_cos(b,a,c)<=0)){ 270 double ang=get_angle(p1,p2); 271 res=fabs((ang/(2.0))*(R*R)); 272 } 273 else 274 if (a>=R&&b>=R&&l<=R&&(get_cos(a,b,c)>0&&get_cos(b,a,c)>0)){ 275 double dist=dist_line(Line(p1,p2)); 276 double len=sqrt(sqr(R)-sqr(dist))*2.0; 277 double ang1=get_angle(p1,p2); 278 double cos2=get_cos(len,R,R); 279 res+=fabs(len*dist/2.0); 280 double ang2=ang1-acos(cos2); 281 res+=fabs((ang2/(2))*(R*R)); 282 } 283 else 284 if ((a>=R&&b<R)||(a<R&&b>=R)){ 285 if (b>a) std::swap(a,b),std::swap(p1,p2); 286 double T=sqr(p1.x-p2.x)+sqr(p1.y-p2.y); 287 Point u=Point(sgn(p1.x-p2.x)*sqrt(sqr(p1.x-p2.x)/T),sgn(p1.y-p2.y)*sqrt(sqr(p1.y-p2.y)/T)); 288 double dist=dist_line(Line(p1,p2)); 289 double len=sqrt(R*R-dist*dist); 290 double len2=sqrt(sqr(dis(p2))-sqr(dist)); 291 if (fabs(dis(p2+u*len2)-dist)<=eps) len+=len2; 292 else len-=len2; 293 Point p=p2+u*len; 294 res+=S(O,p2,p); 295 double ang=get_angle(p1,p); 296 res+=fabs((ang/2.0)*R*R); 297 } 298 int in1=((sgn(c1*p1)*sgn(p1*c2))>=0); 299 int in2=((sgn(c1*p2)*sgn(p2*c2))>=0); 300 if (in1&&in2) return res*rev; 301 if (!in1){ 302 if (dis(p1)<=R){ 303 Point sb=inter(Line(O,c1),Line(p1,p2)); 304 double Di=dis(sb); 305 if (Di<=R) res-=S(O,sb,p1); 306 else{ 307 Point sx=inter(Circle(0,0,R),Line(p1,p2),p1); 308 double ang=get_angle(c1,sx); 309 res-=fabs((ang/2.0)*R*R); 310 res-=S(O,sx,p1); 311 } 312 }else{ 313 Point sb=inter(Line(O,c1),Line(p1,p2)); 314 double Di=dis(sb); 315 if (Di>=R){ 316 double ang=get_angle(c1,p1); 317 res-=fabs((ang/2.0)*R*R); 318 }else{ 319 Point sx=inter(Circle(0,0,R),Line(p1,p2),p1); 320 double ang2=get_angle(p1,sx); 321 res-=fabs((ang2/2.0)*R*R); 322 res-=S(sb,sx,O); 323 } 324 } 325 } 326 if (!in2){ 327 if (dis(p2)<=R){ 328 Point sb=inter(Line(O,c2),Line(p1,p2)); 329 double Di=dis(sb); 330 if (Di<=R) res-=S(O,sb,p2); 331 else{ 332 Point sx=inter(Circle(0,0,R),Line(p2,p1),p2); 333 double ang=get_angle(c2,sx); 334 res-=fabs((ang/2.0)*R*R); 335 res-=S(O,sx,p2); 336 } 337 }else{ 338 Point sb=inter(Line(O,c2),Line(p1,p2)); 339 double Di=dis(sb); 340 if (Di>=R){ 341 double ang=get_angle(c2,p2); 342 res-=fabs((ang/2.0)*R*R); 343 }else{ 344 Point sx=inter(Circle(0,0,R),Line(p2,p1),p2); 345 double ang2=get_angle(p2,sx); 346 res-=fabs((ang2/2.0)*R*R); 347 res-=S(sb,sx,O); 348 } 349 } 350 } 351 return res*rev; 352 } 353 double Gworking2(double a1,double a2,Circle w){ 354 double res=0,r=w.r; 355 Point p1=Point(r*cos(a1),r*sin(a1)); 356 Point p2=Point(r*cos(a2),r*sin(a2)); 357 p[n+1]=p[1]; 358 for (int i=1;i<=n+1;i++) 359 c[i]=Point(p[i].x-w.p.x,p[i].y-w.p.y); 360 for (int i=1;i<=n;i++) 361 res+=gworking2(c[i],c[i+1],p1,p2,r); 362 return res; 363 } 364 void graham(){ 365 int k=1; 366 for (int i=2;i<=n;i++) 367 if (p[i].y<p[k].y||(p[i].x<p[k].x&&p[i].y==p[k].y)) k=i; 368 std::sort(p+2,p+1+n,cmp); 369 int top=1;c[top]=p[1]; 370 for (int i=2;i<=n;i++){ 371 while (top>1&&(c[top]-c[top-1])*(p[i]-c[top])<=0) top--; 372 c[++top]=p[i]; 373 } 374 n=top; 375 for (int i=1;i<=top;i++) 376 p[i]=c[i]; 377 } 378 void Work(Circle p1,Point a1,Point a2){ 379 Point O=p1.p;double r=p1.r; 380 a1.x-=O.x;a2.x-=O.x; 381 a1.y-=O.y;a2.y-=O.y; 382 double x1=atan2(a1.y,a1.x),x2=atan2(a2.y,a2.x); 383 if (x1<0) x1+=2*Pi; 384 if (x2<0) x2+=2*Pi; 385 if (x1<=x2){ 386 cnt++; 387 L[cnt].l=x1; 388 L[cnt].r=x2; 389 }else{ 390 cnt++; 391 L[cnt].l=x1; 392 L[cnt].r=2*Pi; 393 cnt++; 394 L[cnt].l=0.0; 395 L[cnt].r=x2; 396 } 397 } 398 void add(Circle p1,Circle p2){ 399 double x1=p1.p.x,x2=p2.p.x,y1=p1.p.y,y2=p2.p.y,r1=p1.r,r2=p2.r; 400 double A=-2*(x1+x2),B=-2*(y1+y2),C=sqr(x1)+sqr(x2)+sqr(y1)+sqr(y2)-sqr(r1)-sqr(r2); 401 Point S,E; 402 if (fabs(A)<eps){ 403 S=Point(1,(C)/B); 404 E=Point(2,(C)/B); 405 }else 406 if (fabs(B)<eps){ 407 S=Point((C)/A,1); 408 E=Point((C)/A,2); 409 }else{ 410 S=Point(1,(C-A)/B); 411 E=Point(2,(C-2*A)/B); 412 } 413 Line l=Line(S,E); 414 double Dist1=dist_line(p1.p,l); 415 double Dist2=llen(p1.p-S); 416 Point e=evector(E-S); 417 double Dist3=sqrt(sqr(Dist2)-sqr(Dist1)); 418 e=e*Dist3; 419 Point a1,a2; 420 if (fabs(dis(S+e,p1.p)-Dist1)<eps){ 421 S=S+e; 422 } 423 else S=S-e; 424 e=e/Dist3; 425 double Dist4=sqrt(sqr(p1.r)-sqr(llen(S-p1.p))); 426 e=e*Dist4; 427 a1=S+e; 428 a2=S-e; 429 if ((a1-p1.p)*(a2-p1.p)<0) std::swap(a1,a2); 430 //a1放在a2的顺时针方向、 431 if (bigconclude(p1,p2,a1)) std::swap(a1,a2); 432 //a1到a2必须是逆时针。 433 Work(p1,a1,a2); 434 } 435 int main(){ 436 freopen("aerolite.in","r",stdin); 437 freopen("aerolite.out","w",stdout); 438 scanf("%d",&m); 439 for (int i=1;i<=m;i++){ 440 scanf("%lf%lf%lf",&a[i].p.x,&a[i].p.y,&a[i].r); 441 } 442 scanf("%d",&n); 443 for (int i=1;i<=n;i++){ 444 scanf("%lf%lf",&p[i].x,&p[i].y); 445 } 446 graham(); 447 for (int i=1;i<=m;i++) pd[i]=1; 448 for (int i=1;i<=m;i++){ 449 for (int j=1;j<=m;j++) 450 if (i!=j){ 451 if (conclude(a[i],a[j])) {pd[i]=0;break;} 452 } 453 } 454 double ans=0; 455 for (int i=1;i<=m;i++) 456 if (pd[i]){ 457 bool mark=0; 458 for (int j=1;j<=m;j++) 459 if (i!=j&&pd[j]){ 460 if (intersect(a[i],a[j])) {mark=1;break;} 461 } 462 if (!mark) ans+=inter(a[i]),pd[i]=0; 463 } 464 int j=0; 465 for (int i=1;i<=m;i++) 466 if (pd[i]) a[++j]=a[i]; 467 for (int i=1;i<=m;i++) pd[i]=1; 468 for (int i=1;i<=m;i++){ 469 cnt=0; 470 for (int j=1;j<=m;j++) 471 if (i!=j){ 472 add(a[i],a[j]); 473 } 474 std::sort(L+1,L+1+cnt,cmp2); 475 L[0].r=0.0; 476 L[cnt+1].l=2*Pi; 477 double Reach=0.0,Last=0.0; 478 int ww=0; 479 for (int j=1;j<=cnt;j++) 480 if (L[j].l>Reach){ 481 if (j==126) ww++; 482 ans+=Gworking1(Last,Reach,a[i]); 483 Last=L[j].l; 484 ans+=Gworking2(Reach,L[j].l,a[i]); 485 Reach=L[j].r; 486 }else{ 487 Reach=L[j].r; 488 } 489 if (fabs(Reach-2*Pi)<eps){ 490 ans+=Gworking1(Last,Reach,a[i]); 491 }else 492 if (fabs(Reach-2*Pi)>=eps){ 493 ans+=Gworking1(Last,Reach,a[i]); 494 ans+=Gworking2(Reach,2*Pi,a[i]); 495 } 496 } 497 printf("%.8lf\n",ans); 498 return 0; 499 }