BZOJ4541 HNOI2016矿区(平面图转对偶图)
考虑先将平面图转化为对偶图。具体地,将无向边拆成两条有向边。每次考虑找到包围一个区域的所有边。对当前考虑的边,找到该边的反向边在该边终点的出边集中,按极角序排序的后继,这条后继边也是包围该区域的边。这样对偶图就建好了。
考虑怎么用对偶图解决原问题。将外围的无限域也作为对偶图中的一个点,以其为根随便找一棵生成树,计算子树内面积和及面积平方和。对于询问,考虑多边形上每条边,其同时也是对偶图中两点的边。如果该边在生成树中是非树边,扔掉不管;如果是树边,若由父亲指向儿子,则加上儿子权值,否则减掉儿子权值。具体只能感性理解。
注意对偶图中两点间可能有重边,判断是否为非树边时小心一点。因为这个调一年也是没谁了。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<cassert> using namespace std; #define ll long long #define Vector point #define N 400010 #define M 1200010 ll gcd(ll n,ll m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,q,b[N],sur[M],nxt[M],t=-1; map<int,int> id[N],tag; ll lastx,lasty; struct point { int x,y; Vector operator +(const Vector&a) const { return (Vector){x+a.x,y+a.y}; } Vector operator -(const Vector&a) const { return (Vector){x-a.x,y-a.y}; } ll operator *(const Vector&a) const { return 1ll*x*a.y-1ll*y*a.x; } bool operator <(const Vector&a) const { return atan2(x,y)<atan2(a.x,a.y); } }a[N]; struct edge{int x,y;}e[M]; struct data { Vector p;int id; bool operator <(const data&a) const { return p<a.p; } }; vector<data> c[N]; namespace newgraph { int n,p[N],fa[N],t=0,root; ll sum[N],sqr[N],area[N]; struct data{int to,nxt,id;}edge[M]; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].id=z,p[x]=t;} void dfs(int k) { sum[k]=area[k]<<1,sqr[k]=area[k]*area[k]; for (int i=p[k];i;i=edge[i].nxt) if (!fa[edge[i].to]&&edge[i].to!=root) { tag[edge[i].id]=-1,tag[edge[i].id^1]=1; fa[edge[i].to]=k; dfs(edge[i].to); sum[k]+=sum[edge[i].to],sqr[k]+=sqr[edge[i].to]; } } } void addedge(int x,int y) { t++,e[t].x=x,e[t].y=y;id[x][y]=t; c[x].push_back((data){a[y]-a[x],t}); } void build() { for (int i=1;i<=n;i++) if (c[i].size()) { sort(c[i].begin(),c[i].end()); for (int j=0;j<c[i].size()-1;j++) nxt[c[i][j].id]=c[i][j+1].id; nxt[c[i][c[i].size()-1].id]=c[i][0].id; } for (int i=0;i<(m<<1);i++) if (!sur[i]) { ++newgraph::n; int x=i;ll y=0; do { sur[x]=newgraph::n; y+=a[e[x].x]*a[e[x].y]; x=nxt[x^1]; }while (!sur[x]); if (y<0) newgraph::root=newgraph::n; newgraph::area[newgraph::n]=y; } for (int i=0;i<(m<<1);i++) newgraph::addedge(sur[i],sur[i^1],i); newgraph::dfs(newgraph::root); } signed main() { #ifndef ONLINE_JUDGE freopen("bzoj4541.in","r",stdin); freopen("bzoj4541.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),m=read(),q=read(); for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } build(); while (q--) { int t=(read()+lastx)%n+1; for (int i=1;i<=t;i++) b[i]=(read()+lastx)%n+1; lastx=0,lasty=0; for (int i=1;i<=t;i++) { int x=tag[id[b[i]][b[i%t+1]]]; if (x) { int y=x==1?sur[id[b[i]][b[i%t+1]]]:sur[id[b[i%t+1]][b[i]]]; lasty+=x*newgraph::sum[y],lastx+=x*newgraph::sqr[y]; } } ll tmp=gcd(lastx,lasty); lastx/=tmp,lasty/=tmp; printf(LL,lastx),printf(LL,lasty),printf("\n"); } return 0; }