题目描述
平面图&对偶图
平面图的定义:可以放在笛卡尔坐标系中,边只会在给定顶点处相交
把平面图中的每个区域+无穷域当作一个点,每条边变成两边的区域的连边,即为对偶图
把一条边拆成两条,每次找一个点,对于一条边找逆时针的下一条边(总方向是顺时针),直到找出一个环
因此要找一个块的内侧就可以按照上面的顺序寻找,找到的边所对应的块即为内侧
从u--v中u在v中的编号可以排序+二分,每条边只会经过一次
对于最小割可以把源汇连起来作为一个新的区域,从该块到无穷域的最短路即为最小割
题解
总面积很好求,问题是怎么求面积的平方和
把对偶图建一棵生成树,以无穷域为根统计子树和
无穷域找法:可以先判掉最外圈,具体为找y最大的点,然后逆时针寻找
也可以直接找面积为负的区域
如果一个询问经过的边不在生成树上就不管,如果内侧块(即当前边所对应的块,在顺时针方向)在生成树上为儿子就加上答案,否则减去答案
画一下就可以发现这样是对的
注意题目给出询问点是逆时针,所以要反过来
code
很好写(3.7k)
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
//#define file
using namespace std;
struct p{
int x,y;
} a[200001];
struct type{
int x,y;
double s;
} b[1200001];
struct Type{
int x,id;
} B[1200001];
int aa[800001][2];
int ls[400002];
bool bz[1200001];
int c[1200001];
int C[1200001];
int st[200002];
long long S[400002];
long long S2[400002];
int fa[400002];
int FA[400002];
int q[200002];
int n,m,Q,i,j,k,l,K,L,tot,N,Tot,mx,mx2,len,x,X,y;
long long lsans,ans1,ans2,Gcd;
char ch;
void New(int x,int y)
{
++len;
aa[len][0]=y;
aa[len][1]=ls[x];
ls[x]=len;
}
int getint()
{
int x=0,k=1;
ch=getchar();
while (ch<'0' || ch>'9') k=(ch=='-')?-1:k,ch=getchar();
while (ch>='0' && ch<='9') x=x*10+(ch-'0'),ch=getchar();
return x*k;
}
long long cj(p a,p b)
{
return b.x*a.y-a.x*b.y;
}
bool cmp(type a,type b) {return a.x<b.x || a.x==b.x && a.s<b.s;}
bool Cmp(Type a,Type b) {return a.x<b.x;}
double ang(p a,p b)
{
int x=b.x-a.x,y=b.y-a.y;
if (!y)
{
if (x>0)
return 0;
return M_PI;
}
if (!x)
{
if (y>0)
return M_PI/2;
return M_PI*3/2;
}
if (x>0 && y>0) return atan(1.0*y/x);
if (x>0 && y<0) return atan(1.0*y/x)+M_PI*2;
return atan(1.0*y/x)+M_PI;
}
long long gcd(long long a,long long b)
{
long long r=a%b;
while (r)
a=b,b=r,r=a%b;
return b;
}
int find(int t,int x)
{
int l=st[t],r=st[t+1]-1,mid;
while (l<r)
{
mid=(l+r)/2;
if (B[mid].x<x)
l=mid+1;
else
r=mid;
}
return B[l].id;
}
void work(int k,int l)
{
int K,L;
while (!bz[l])
{
S[N]+=cj(a[k],a[b[l].y]);
bz[l]=1;
c[l]=N;
K=b[l].y;
L=find(K,k);
if (L==st[K+1]-1)
L=st[K];
else
++L;
k=K,l=L;
}
S2[N]=S[N]*S[N];
}
int gf(int t)
{
if (fa[t]==t) return t;
fa[t]=gf(fa[t]);
return fa[t];
}
void dfs(int Fa,int t)
{
int i;
FA[t]=Fa;
for (i=ls[t]; i; i=aa[i][1])
if (aa[i][0]!=Fa)
{
dfs(t,aa[i][0]);
S2[t]+=S2[aa[i][0]];
}
}
int main()
{
#ifdef file
freopen("loj2052_8.in","r",stdin);
#endif
n=getint();m=getint();Q=getint();
fo(i,1,n)
a[i].x=getint(),a[i].y=getint();
fo(i,1,m)
{
j=getint(),k=getint();
b[++tot]={j,k,ang(a[j],a[k])};
b[++tot]={k,j,ang(a[k],a[j])};
}
sort(b+1,b+tot+1,cmp);
fo(i,1,tot) B[i]={b[i].y,i};
j=1;
fo(i,1,n)
{
st[i]=j;
while (j<=tot && b[j].x==i)
++j;
}
st[n+1]=tot+1;
fo(i,1,n)
if (st[i]<st[i+1])
sort(B+st[i],B+(st[i+1]-1)+1,Cmp);
// ---外边界
mx=-2133333333;
fo(i,1,n)
if (a[i].y>mx)
mx=a[i].y,mx2=i;
N=1;
fo(j,st[mx2],st[mx2+1]-1)
if (b[j].s>=M_PI-0.00000001)
{
work(mx2,j);
break;
}
// ---对偶图
fo(i,1,n)
{
fo(j,st[i],st[i+1]-1)
if (!bz[j])
{
++N;
work(i,j);
}
}
fo(i,1,N) fa[i]=i;
// ---生成树
fo(i,1,n)
{
fo(j,st[i],st[i+1]-1)
{
k=find(b[j].y,i);
C[j]=c[k];
if (gf(c[j])!=gf(c[k]))
{
fa[fa[c[j]]]=fa[c[k]];
bz[j]=bz[k]=0;
New(c[j],c[k]);
New(c[k],c[j]);
}
}
}
dfs(0,1);
// ---
for (;Q;--Q)
{
lsans=ans1,ans1=ans2=0;
Tot=getint();Tot=(Tot+lsans%n)%n+1;
fo(i,1,Tot) q[i]=getint(),q[i]=(q[i]+lsans%n)%n+1;
fd(i,Tot,1)
{
j=find(q[i%Tot+1],q[i]);
if (!bz[j])
{
if (FA[c[j]]==C[j])
ans1+=S2[c[j]];
else
if (FA[C[j]]==c[j])
ans1-=S2[C[j]];
}
ans2+=cj(a[q[i%Tot+1]],a[q[i]]);
}
ans2*=2;
Gcd=gcd(ans1,ans2);
ans1/=Gcd,ans2/=Gcd;
printf("%lld %lld
",ans1,ans2);
}
}