! HNOI2016矿区



平面图转对偶图(把面转为点,点转为面)

构建方法:

  1. 双向边变两个单向边,这样每条边属于一个面,把每个点的出边按极角排序
  2. 从一条边出发,不停找下一条边(下一个点向左旋,离我最近的边),最后会形成一块区域。不停找,把所有区域找出来

然后以无域界为根(叉积算出为负)建立一棵生成树

然后就是非常妙的地方了

查询时,一次遍历每条边,若不在树上则跳过,否则若这条边所在的面是儿子就加上子树面积,否则减去

#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);
}
原文地址:https://www.cnblogs.com/aurora2004/p/12657974.html