平面图转对偶图(把面转为点,点转为面)
构建方法:
- 双向边变两个单向边,这样每条边属于一个面,把每个点的出边按极角排序
- 从一条边出发,不停找下一条边(下一个点向左旋,离我最近的边),最后会形成一块区域。不停找,把所有区域找出来
然后以无域界为根(叉积算出为负)建立一棵生成树
然后就是非常妙的地方了
查询时,一次遍历每条边,若不在树上则跳过,否则若这条边所在的面是儿子就加上子树面积,否则减去
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=2e5+4,M=12e5+4;
const double eps=1e-6;
struct poin{
int x,y;
inline poin operator -(const poin &a)const{
return (poin){x-a.x,y-a.y};
}
inline int operator *(const poin &a)const{
return x*a.y-y*a.x;
}
};
struct edge{
int id,u,v;
double sl;
inline bool operator <(const edge &x)const{
return fabs(sl-x.sl)<eps?v<x.v:sl<x.sl;
}
};
vector<edge>h[N],t[M];
edge e[M];
poin p[N];
int n,m,Q,rt,cnt=1,cn,ans1,ans2;
int nxt[M],bel[M],vis[M],fa[M],ins[M],s[M],s2[M],z[N];
inline void add(int u,int v){
e[++cnt]=(edge){cnt,u,v,atan2(p[v].y-p[u].y,p[v].x-p[u].x)};
h[u].push_back(e[cnt]);
}
inline void build(){
for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end());
for(int i=2,v;i<=cnt;i++){
v=e[i].v;
auto it=lower_bound(h[v].begin(),h[v].end(),e[i^1]);
if(it==h[v].begin())it=h[v].end();
nxt[i]=(*--it).id;
}
for(int i=2;i<=cnt;i++){
if(bel[i])continue;
++cn;
for(int j=i;!bel[j];bel[j]=cn,j=nxt[j])
s[cn]+=p[e[j].u]*p[e[j].v];
if(s[cn]<=0)rt=cn;
}
for(int i=2;i<=cnt;i++)
t[bel[i]].push_back((edge){i,bel[i],bel[i^1]});
}
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
void dfs(int x){
s2[x]=s[x]*s[x];s[x]<<=1;
vis[x]=1;
for(auto i:t[x]){
if(vis[i.v])continue;
fa[i.v]=x;
ins[i.id]=ins[i.id^1]=1;
dfs(i.v);
s2[x]+=s2[i.v];
s[x]+=s[i.v];
}
}
signed main(){
n=read();m=read();Q=read();
for(int i=1;i<=n;i++){
p[i].x=read();p[i].y=read();
}
for(int i=1,u,v;i<=m;i++){
u=read();v=read();
add(u,v);add(v,u);
}
build();
dfs(rt);
int d,u,v,j,gd;
edge x;
while(Q--){
d=(read()+ans2)%n+1;
for(int i=1;i<=d;i++)z[i]=(read()+ans2)%n+1;
z[d+1]=z[1];
ans1=ans2=0;
for(int i=1;i<=d;i++){
u=z[i];v=z[i+1];
x=(edge){0,u,v,atan2(p[v].y-p[u].y,p[v].x-p[u].x)};
auto it=lower_bound(h[u].begin(),h[u].end(),x);
j=(*it).id;
if(!ins[j])continue;
if(fa[bel[j]]==bel[j^1]){ans1+=s[bel[j]];ans2+=s2[bel[j]];}
else{ans1-=s[bel[j^1]];ans2-=s2[bel[j^1]];}
}
gd=gcd(ans1,ans2);
ans1/=gd;ans2/=gd;
cout<<ans2<<" "<<ans1<<"
";
}
return (0-0);
}