bzoj4561
本来是在做计算几何的,莫名其妙来到了这道题,看了题解之后感觉挺有意思的。
我们用扫描线+平衡树,扫到圆的左端时插入两个点,分别表示圆的上弧和下弧,扫到右端点的时候删除他们。由于圆不相交,所以圆弧的相对位置不会改变,所以平衡树的形态也不会改变。并且可以通过圆的解析式轻松求出当前横坐标下每个圆弧所对应的纵坐标。那么就可以很轻松的完成插入和删除操作。
答案是什么呢?我们只需要对于每个圆,看一下他插入时平衡树中的后继是上弧还是下弧,下弧说明两个圆是并列关系,上弧说明是包含关系,没后继说明只被自己覆盖,便可得知当前圆的被覆盖情况。奇数个说明面积需要加进答案,反之减去。
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define dl double 4 #define P pair<int,int> 5 using namespace std; 6 const int inf=2e5+10; 7 int n; 8 struct circle{ 9 int x,y,r; 10 bool tag; 11 }c[inf]; 12 struct smx{ 13 int x; 14 int id,opt; 15 bool operator < (const smx &o)const{return x<o.x;} 16 }s[inf<<1]; 17 struct node{ 18 int ls,rs; 19 int id,opt,siz; 20 int rnd; 21 }t[inf<<1]; 22 int rt,sz; 23 void upd(int x){t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;} 24 P split(int x,int k){ 25 if(!x)return P(0,0); 26 P tmp; 27 if(t[t[x].ls].siz >=k){ 28 tmp=split(t[x].ls,k); 29 t[x].ls=tmp.second; 30 upd(x); 31 tmp.second=x; 32 } 33 else { 34 tmp=split(t[x].rs,k-t[t[x].ls].siz-1); 35 t[x].rs=tmp.first; 36 upd(x); 37 tmp.first=x; 38 } 39 return tmp; 40 } 41 int merge(int x,int y){ 42 if(!x || !y)return x+y; 43 if(t[x].rnd < t[y].rnd){ 44 t[x].rs=merge(t[x].rs,y); 45 upd(x);return x; 46 } 47 else { 48 t[y].ls=merge(x,t[y].ls); 49 upd(y);return y; 50 } 51 } 52 dl get_y(int id,int x,int opt){ 53 dl tmp=sqrt((dl)(1ll*c[id].r*c[id].r-1ll*(x-c[id].x)*(x-c[id].x))); 54 return c[id].y+opt*tmp; 55 } 56 int rank(int o,int x,int y){ 57 if(!o)return 0; 58 if(get_y(t[o].id,x,t[o].opt) >= y)return rank(t[o].ls,x,y); 59 else return t[t[o].ls].siz+1+rank(t[o].rs,x,y); 60 } 61 node kth(int o,int x){ 62 if(t[t[o].ls].siz+1==x)return t[o]; 63 if(t[t[o].ls].siz >= x)return kth(t[o].ls,x); 64 else return kth(t[o].rs,x-t[t[o].ls].siz-1); 65 } 66 void del(int x,int y){ 67 int u=rank(rt,x,y); 68 P tmp=split(rt,u); 69 rt=merge(tmp.first,split(tmp.second,2).second); 70 } 71 int get_new(int id,int opt){ 72 sz++;t[sz].id=id;t[sz].opt=opt; 73 t[sz].siz=1;t[sz].rnd=((rand()<<12)+rand())%10000000; 74 return sz; 75 } 76 void insert(int id,int opt){ 77 int x=c[id].x-c[id].r,y=c[id].y; 78 int u=rank(rt,x,y); 79 P tmp=split(rt,u); 80 rt=merge(merge(tmp.first,get_new(id,opt)),tmp.second); 81 } 82 int main(){ 83 scanf("%d",&n); 84 for(int i=1;i<=n;i++){ 85 scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].r); 86 s[i*2-1]=(smx){c[i].x-c[i].r,i,1}; 87 s[i*2]=(smx){c[i].x+c[i].r,i,-1}; 88 } 89 sort(s+1,s+2*n+1); 90 for(int i=1;i<=2*n;i++){ 91 if(s[i].opt==-1){//当前treap里面只存在两个点纵坐标为s[i].y,因为题目保证不相交 92 del(s[i].x,c[s[i].id].y); 93 } 94 else { 95 int u=rank(rt,s[i].x,c[s[i].id].y); 96 if(u==t[rt].siz)c[s[i].id].tag=1; 97 else { 98 node v=kth(rt,u+1); 99 if(v.opt==1)c[s[i].id].tag=c[v.id].tag^1;//1是上弧 100 else c[s[i].id].tag=c[v.id].tag; 101 }//cout<<c[s[i].id].tag<<" "<<s[i].id<<endl; 102 insert(s[i].id,1);insert(s[i].id,-1); 103 } 104 } 105 LL ans=0; 106 for(int i=1;i<=n;i++) 107 if(c[i].tag)ans+=1ll*c[i].r*c[i].r; 108 else ans-=1ll*c[i].r*c[i].r; 109 printf("%lld\n",ans); 110 return 0; 111 }
bzoj1020
这道题网上都是用的非官方解法做的。具体是搜索+剪枝。我不能很好的理解题解的一些细节,甚至觉得ydc的题解有问题?...大概是我的问题。可能是理解的不同。我知道判断是否入队的时候直接判断R>=ans肯定是不对的...可是我也不清楚为什么他们+0.005就过了,我加了之后wa1个点,而那个点似乎是因为精度问题,改成一个过不了样例的eps就过去了。所以我也无权对这道题做评价了。我唯一的收获就是写了一道比较长的计算几何?也不算长。并且写了判断点在多边形内?我不会很好的处理特殊情况于是我就随机化了一下...
1 #include<bits/stdc++.h> 2 #define dl double 3 #define pi acos(-1) 4 using namespace std; 5 const dl eps=1e-5; 6 struct Point{dl x,y;}; 7 typedef Point Vector; 8 Point operator + (Point a,Point b){return (Point){a.x+b.x,a.y+b.y};} 9 Point operator / (Point a,dl b){return (Point){a.x/b,a.y/b};} 10 Vector operator - (Point a,Point b){return (Vector){a.x-b.x,a.y-b.y};} 11 Vector operator * (Vector a,dl b){return (Vector){a.x*b,a.y*b};} 12 dl dis(Point a,Point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));} 13 dl Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} 14 dl Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;} 15 struct segment{Point a,b;}; 16 int C,N; 17 bool on(Point a,Point fro,Point to){ 18 return abs(Cross(fro-a,to-a))<=eps && Dot(fro-a,to-a)<=eps; 19 } 20 bool inter(Point a1,Point b1,Point a2,Point b2){ 21 return (Cross(b1-a1,a2-a1) * Cross(b1-a1,b2-a1) <= eps) && (Cross(a2-b2,a1-b2) * Cross(a2-b2,b1-b2) <= eps); 22 } 23 struct inland{ 24 int m; 25 Point t[35]; 26 bool in(Point a){ 27 for(int i=1;i<=m;i++) 28 if(on(a,t[i],t[i%m+1]))return 1; 29 Point tmp[6]; 30 tmp[1].x=10001+rand(),tmp[1].y=10001+rand(); 31 tmp[2].x=-(10001+rand()),tmp[2].y=10001+rand(); 32 tmp[3].x=10001+rand(),tmp[3].y=-(10001+rand()); 33 tmp[4].x=-(10001+rand()),tmp[4].y=-(10001+rand()); 34 tmp[5].x=10001+rand(),tmp[5].y=10001+rand(); 35 int cnt1=0,cnt2=0; 36 for(int i=1;i<=5;i++){ 37 int cnt=0; 38 for(int j=1;j<=m;j++) 39 if(inter(a,tmp[i],t[j],t[j%m+1]))cnt++; 40 if(cnt&1)cnt1++; 41 else cnt2++; 42 } 43 return cnt1>cnt2; 44 } 45 }land[25]; 46 Point tmp[25]; 47 queue<segment>S; 48 Vector rot(Vector a,dl b){ 49 return (Vector){a.x*cos(b)-a.y*sin(b),a.x*sin(b)+a.y*cos(b)}; 50 } 51 Point get(Point a,Point fro,Point to){ 52 if(Dot(to-fro,a-fro)<=eps)return fro; 53 if(Dot(fro-to,a-to)<=eps)return to; 54 Vector v1=to-fro,v2=rot(v1,pi/2); 55 Vector u=fro-a; 56 dl t2=Cross(u,v1)/Cross(v2,v1); 57 return a+v2*t2; 58 } 59 Point find(Point a){ 60 for(int i=1;i<=C;i++) 61 if(land[i].in(a))return a; 62 dl ans=1e9; 63 Point ret; 64 for(int i=1;i<=C;i++) 65 for(int j=1;j<=land[i].m;j++){ 66 Point now=get(a,land[i].t[j],land[i].t[j%land[i].m+1]); 67 dl d=dis(now,a); 68 if(d < ans){ans=d;ret=now;} 69 } 70 return ret; 71 } 72 dl ans; 73 int main(){ 74 srand(time(NULL)); 75 scanf("%d%d",&C,&N); 76 for(int i=1;i<=N;i++)scanf("%lf%lf",&tmp[i].x,&tmp[i].y); 77 for(int i=1;i<=C;i++){ 78 scanf("%d",&land[i].m); 79 for(int j=1;j<=land[i].m;j++)scanf("%lf%lf",&land[i].t[j].x,&land[i].t[j].y); 80 } 81 for(int i=2;i<=N;i++)S.push((segment){tmp[i-1],tmp[i]}); 82 while(!S.empty()){ 83 segment u=S.front(); 84 S.pop(); 85 Point p1=find(u.a),p2=find(u.b); 86 Point l=u.a,r=u.b; 87 ans=max(ans,dis(l,p1));ans=max(ans,dis(r,p2)); 88 while(dis(l,r) > eps){//二分出的点有两种情况,一种是到p1,p2距离相等,一种是在l或者r处 89 Point p=(l+r)/2; 90 if(dis(p,p1) < dis(p,p2))l=p; 91 else r=p; 92 } 93 dl R=min(dis(l,p1),dis(l,p2)); 94 if(R <= ans+eps)continue;//题解说要+0.005,我先不加看看行不行 95 ans=max(ans,dis(l,find(l))); 96 S.push((segment){u.a,l});S.push((segment){l,u.b}); 97 } 98 printf("%.2lf\n",ans); 99 return 0; 100 }
bzoj1132
这题就清新多了...除了卡double以外,必须longlong才能过。
叉积是具有分配率的a x (b+c)=a x b + a x c
我们按纵坐标从小到大枚举,枚举完当前点后删除它。然后对于当前存在的点按极角排个序,发现扫一遍记录一下向量的前缀和并叉积求面积即可。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int inf=3005; 5 int n; 6 struct Point{int x,y;}t[inf]; 7 typedef Point Vector; 8 Vector operator - (Point a,Point b){return (Vector){a.x-b.x,a.y-b.y};} 9 Vector operator + (Vector a,Vector b){return (Vector){a.x+b.x,a.y+b.y};} 10 LL Cross(Vector a,Vector b){return 1ll*a.x*b.y-1ll*a.y*b.x;} 11 bool cmp1(Point a,Point b){return a.y<b.y || (a.y==b.y && a.x<b.x);} 12 Point now; 13 bool cmp2(Point a,Point b){return Cross(a-now,b-now)<0;} 14 LL ans; 15 int main(){ 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++)scanf("%d%d",&t[i].x,&t[i].y); 18 sort(t+1,t+n+1,cmp1); 19 for(int i=1;i<=n;i++){ 20 now=t[i]; 21 sort(t+i+1,t+n+1,cmp2); 22 Vector S=(Point){0,0}; 23 for(int j=i+1;j<=n;j++){ 24 ans+=Cross(t[j]-now,S); 25 S=S+(t[j]-now); 26 } 27 sort(t+i+1,t+n+1,cmp1); 28 } 29 if(ans&1)printf("%lld.5\n",ans/2); 30 else printf("%lld.0\n",ans/2); 31 return 0; 32 }
bzoj1069
旋转卡壳的模板题吧,算是又温习了一下。
枚举对角的两个点,另外两个点也在枚举过程中不断调整使得面积最大。
1 #include<bits/stdc++.h> 2 #define dl double 3 using namespace std; 4 const int inf=2005; 5 const dl eps=1e-7; 6 struct Point{dl x,y;}t[inf]; 7 typedef Point Vector; 8 Vector operator - (Point a,Point b){return (Point){a.x-b.x,a.y-b.y};} 9 dl Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} 10 dl Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;} 11 dl Length(Vector a){return sqrt(Dot(a,a));} 12 bool cmp1(Point a,Point b){return a.x<b.x || (a.x==b.x && a.y<b.y);} 13 bool cmp2(Point a,Point b){return Cross(a-t[1],b-t[1])>eps || (abs(Cross(a-t[1],b-t[1]))<=eps && Length(a-t[1])<Length(b-t[1]));} 14 Point sta[inf]; 15 int top,n; 16 dl mx; 17 int main(){ 18 scanf("%d",&n); 19 for(int i=1;i<=n;i++)scanf("%lf%lf",&t[i].x,&t[i].y); 20 sort(t+1,t+n+1,cmp1); 21 sort(t+2,t+n+1,cmp2); 22 sta[++top]=t[1]; 23 for(int i=2;i<=n;i++){ 24 while(top>=2 && Cross(sta[top]-sta[top-1],t[i]-sta[top-1])<eps)top--; 25 sta[++top]=t[i]; 26 } 27 for(int i=1;i<=top;i++)t[i]=sta[i]; 28 n=top; 29 for(int i=1;i<=n;i++){ 30 int p1=i%n+1,p2=p1%n+1,p3=p2%n+1; 31 for(int j=1;j<=n-3;j++,p2=p2%n+1){ 32 while(p1%n+1!=p2 && Cross(t[p1%n+1]-t[i],t[p2]-t[i]) > Cross(t[p1]-t[i],t[p2]-t[i]))p1=p1%n+1; 33 while(p3%n+1!=i && Cross(t[p2]-t[i],t[p3%n+1]-t[i]) > Cross(t[p2]-t[i],t[p3]-t[i]))p3=p3%n+1; 34 mx=max(mx,Cross(t[p1]-t[i],t[p2]-t[i])+Cross(t[p2]-t[i],t[p3]-t[i])); 35 } 36 } 37 printf("%.3lf\n",mx/2); 38 return 0; 39 }