平面图转对偶图完全不会啊,只好学一下了
Orz了清哥的代码,感觉思路很清晰啊
顺手写个学习笔记吧。
方便起见编号为i的边与编号为i^1的边互为反向边。
对于每个点进行极角排序,同时用一个数组表示该边的下一条边。
于是乎我们从边i出发,到i的反向边的下一条边,画个图可以发现这么走形成的域一定在这些边的右边,并且他们之中仅包含一个域(因为是贴着右边走的),这个时候可以用叉积算下面积,如果面积为负,那么一定是贴着最外面走的,右边是无穷域。
所以我们得到了每条有向边右边的域,每条有向边在对偶图中也对应着一条有向边,我们不妨设对偶图中的有向边由i的右边的域指向i的左边的域。
然后对偶图就建好了。
其实思路很简单的
那么考虑一下这道题,我们以无穷域为根节点搜索出一棵dfs树
那么dfs树上的边在开发区域中肯定会进♂进♂出♂出,但是这样进♂进♂出♂出没有快感啊,怎么办呢
我们考虑求出dfs树上每个节点子树的权值和,那么进♂去的时候加上子树的权值和,出来的时候减去剩下子树的权值和,于是就得到答案(有快感)了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; int read(){char ch=getchar();int x=0,f=1;while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} #define rep(i,l,r) for(int i=l;i<=r;i++) #define per(i,r,l) for(int i=r;i>=l;i--) const int N=200000+5; const int M=600000+5; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} struct point{ll x,y;}p[N]; point operator - (point a,point b){return (point){a.x-b.x,a.y-b.y};} ll cross(point a,point b){return a.x*b.y-a.y*b.x;} ll cross(point a,point b,point c){return cross(b-a,c-a);} struct Edge{int to,next;}e[M<<1]; int head[N<<2]; struct edge{ int u,v,ri; double slop; edge(){} edge(int _u,int _v):u(_u),v(_v),ri(0){ slop=atan2(p[v].y-p[u].y,p[v].x-p[u].x); } }o[M<<1]; void ins(int i){e[i]=(Edge){o[i^1].ri,head[o[i].ri]};head[o[i].ri]=i;} vector<int>g[N]; bool cmp(int i,int j){return o[i].slop<o[j].slop;} bool pmc(int i,int j){return o[i].v<o[j].v;} int next[M<<1],q[M<<1]; ll area[N<<2],sum[N<<2][2]; int dual,root,fa[N<<2]; bool vis[N<<2],tree[M<<1]; void dfs(int u){ vis[u]=true; if(u^root)sum[u][0]=area[u]*area[u],sum[u][1]=area[u]*2; for(int i=head[u];i;i=e[i].next){ int v=e[i].to;if(vis[v])continue; fa[v]=u;tree[i]=tree[i^1]=true;dfs(v); sum[u][0]+=sum[v][0];sum[u][1]+=sum[v][1]; } } int find(int u,int v){ int l=0,r=g[u].size()-1; while(l<=r){ int mid=(l+r)/2; if(v<=o[g[u][mid]].v)r=mid-1; else l=mid+1; } return g[u][r+1]; } int main(){ //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int n,m,k;n=read();m=read();k=read(); rep(i,1,n)p[i].x=read(),p[i].y=read(); rep(i,1,m){ int u,v;u=read();v=read(); o[i<<1]=edge(u,v);o[i<<1|1]=edge(v,u); g[u].push_back(i<<1);g[v].push_back(i<<1|1); } rep(i,1,n){ sort(g[i].begin(),g[i].end(),cmp); for(int j=0,k=g[i].size();j<k;j++) next[g[i][j]]=g[i][(j+1)%k]; sort(g[i].begin(),g[i].end(),pmc); } rep(i,2,(m<<1|1)) if(!o[i].ri){ int j=i;dual++;q[0]=0; do o[j].ri=dual,q[++q[0]]=o[j].v,j=next[j^1];while(j^i); rep(j,2,q[0]-1) area[dual]+=cross(p[q[1]],p[q[j+1]],p[q[j]]); if(area[dual]<0)root=dual; } rep(i,2,(m<<1|1))ins(i); dfs(root); ll ans1=0,ans2=0; while(k--){ q[0]=read();q[0]=(q[0]+ans1)%n+1; rep(i,1,q[0])q[i]=read(),q[i]=(q[i]+ans1)%n+1; ans1=0;ans2=0; rep(i,1,q[0]){ int u=q[i],v=q[i%q[0]+1],k=find(u,v); if(tree[k]){ if(fa[o[k].ri]==o[k^1].ri) ans1-=sum[o[k].ri][0],ans2-=sum[o[k].ri][1]; else ans1+=sum[o[k^1].ri][0],ans2+=sum[o[k^1].ri][1]; } } ll d=gcd(ans1,ans2);ans1/=d,ans2/=d; printf("%lld %lld\n",ans1,ans2); } return 0; }