CF223E Planar Graph
Link
建立这样的一个网络模型:每个点自带\(1\)的流量,所有流量沿着边进行流动,最后汇聚到汇点。
也就是说每条边在某个方向上可能有流量,除了汇点以外一个点流出的流量比流入的流量大一。
那么一个多边形(环)中的点的个数就是流出环的流量总和减去流入环的流量总和。
我们不妨选择横坐标最小的点作为汇点。
以汇点为根建出一棵有根生成树,那么每个点往父亲的的流量就是该点的子树大小。
在一次询问中,我们考虑对于多边形边界上的所有点计算出它往多边形外的流量。
注意到对于多边形边界上的一个点,把它的所有出边按极角排序,那么往多边形外走的边是一段连续的区间,预处理前缀和即可。
总的时间复杂度为\(O(n+m\log m+\sum k)\)。
#include<map>
#include<cmath>
#include<cctype>
#include<cstdio>
#include<vector>
#include<algorithm>
using f64=double;
using i64=long long;
using pi=std::pair<int,int>;
const int N=100007,M=200007;
int tot=1,head[N],vis[N],sum[N],b[N];char ibuf[1<<22|1],*iS=ibuf;
struct vec{int x,y;}a[N];struct edge{int v,w,rank,next;f64 theta;}e[M];
std::map<pi,int>id;std::vector<int>pre[N];
int read(){int x=0,f=1;while(isspace(*iS))++iS;if(*iS=='-')++iS,f=-1;while(isdigit(*iS))(x*=10)+=*iS++&15;return f*x;}
void add(int u,int v){e[++tot].v=v,e[tot].next=head[u],head[u]=id[pi(u,v)]=tot;}
int dfs(int u)
{
int flow=vis[u]=1;
for(int i=head[u],f;i;i=e[i].next) if(!vis[e[i].v]) f=dfs(e[i].v),e[i].w+=f,e[i^1].w-=f,flow+=f;
return flow;
}
void solve()
{
int k=read(),ans=k;i64 mu=0;
for(int i=0;i<k;++i) b[i]=read();
for(int i=0;i<k;++i) mu+=1ll*a[b[i]].x*a[b[(i+1)%k]].y-1ll*a[b[i]].y*a[b[(i+1)%k]].x;
if(mu<0) std::reverse(b,b+k);
for(int i=0,l,r;i<k;++i)
{
l=e[id[pi(b[i],b[(i+1)%k])]].rank,r=e[id[pi(b[i],b[(i+k-1)%k])]].rank,ans+=pre[b[i]][r]-pre[b[i]][l-1];
if(l>r) ans+=sum[b[i]];
}
printf("%d\n",ans);
}
int main()
{
fread(ibuf,1,1<<22,stdin);
int n=read(),m=read(),root;
for(int i=1,u,v;i<=m;++i) u=read(),v=read(),add(u,v),add(v,u);
for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();
for(int i=root=1;i<=n;++i) if(a[i].x<a[root].x) root=i;
dfs(root);
for(int u=1;u<=n;++u)
{
pre[u].push_back(0);
for(int i=head[u];i;i=e[i].next) pre[u].push_back(i),sum[u]+=e[i].w,e[i].theta=atan2(a[e[i].v].y-a[u].y,a[e[i].v].x-a[u].x);
std::sort(pre[u].begin(),pre[u].end(),[](int i,int j){return !i? 1:!j? 0:e[i].theta<e[j].theta;});
for(int i=1;i<(int)pre[u].size();++i) e[pre[u][i]].rank=i,pre[u][i]=pre[u][i-1]+e[pre[u][i]].w;
}
for(int q=read();q;--q) solve();
}