BZOJ2960 : 跨平面
平面图求域之后增加超级根,然后建图求最小树形图即可。
#include<cstdio> #include<cmath> #include<set> #include<algorithm> using namespace std; typedef long long ll; const int N=3010,M=10010,inf=0x7fffffff; int n,m,q,cnt,i,x,y,z1,z2; struct P{ int x,y; P(){} P(int _x,int _y){x=_x,y=_y;} ll operator*(const P&b){return 1LL*x*b.y-1LL*y*b.x;} }a[N],b[M]; struct E{ int x,y,z;double o; E(){} E(int _x,int _y,int _z){x=_x,y=_y,z=_z,o=atan2(a[y].x-a[x].x,a[y].y-a[x].y);} }e[M]; bool del[M];int from[M]; namespace GetArea{ struct cmp{bool operator()(int a,int b){return e[a].o<e[b].o;}}; set<int,cmp>g[N];set<int,cmp>::iterator k;int i,j,q[M],t; void work(){ for(i=0;i<m+m;i++)if(!del[i]){ for(q[t=1]=j=i;;q[++t]=j=*k){ k=g[e[j].y].find(j^1);k++; if(k==g[e[j].y].end())k=g[e[j].y].begin(); if(*k==i)break; } ll s=0; for(j=1;j<=t;j++)s+=a[e[q[j]].x]*a[e[q[j]].y],del[q[j]]=1; if(s<0)continue; for(cnt++,j=1;j<=t;j++)from[q[j]]=cnt; } } } namespace DMST{ int n,size,pre[N],id[N],vis[N],in[N]; struct EDGE{ int u,v,cost; EDGE(){} EDGE(int a,int b,int c):u(a),v(b),cost(c){} }E[M]; void init(int _n){n=_n,size=0;} void add(int u,int v,int w){E[size++]=EDGE(u,v,w);} int dmst(int root){ int u,v,cnt,ret=0,i; while(1){ for(i=0;i<n;i++)in[i]=inf; for(i=0;i<size;i++){ u=E[i].u,v=E[i].v; if(E[i].cost<in[v]&&u!=v)pre[v]=u,in[v]=E[i].cost; } for(cnt=in[root]=i=0;i<n;i++)id[i]=vis[i]=-1; for(i=0;i<n;i++){ ret+=in[i],v=i; while(vis[v]!=i&&id[v]==-1&&v!=root)vis[v]=i,v=pre[v]; if(v!=root&&id[v]==-1){ for(u=pre[v];u!=v;u=pre[u])id[u]=cnt; id[v]=cnt++; } } if(!cnt)break; for(i=0;i<n;i++)if(id[i]==-1)id[i]=cnt++; for(i=0;v=E[i].v,i<size;i++){ E[i].u=id[E[i].u],E[i].v=id[E[i].v]; if(E[i].u!=E[i].v)E[i].cost-=in[v]; } n=cnt,root=id[root]; } return ret; } void work(int _n){ n=_n; int i,tot=1; for(i=0;i<m+m;i++)if(e[i].z)add(from[i],from[i^1],e[i].z),tot+=e[i].z; for(i=0;i<n-1;i++)add(n-1,i,tot); printf("%d",dmst(n-1)-tot); } } int main(){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%d%d",&x,&y); a[i]=P(x,y); } for(i=0;i<m;i++){ scanf("%d%d%d%d",&x,&y,&z1,&z2); e[i<<1]=E(x,y,z1); e[i<<1|1]=E(y,x,z2); } for(i=0;i<m+m;i++)GetArea::g[e[i].x].insert(i); GetArea::work(); DMST::work(cnt+2); return 0; }