给定n个点m条边的平面图,q个询问,每次询问给出k个点,问这k个点的导出子平面图的域(不包括无穷域)的个数
n<=5e4,m<=2e5,q<=1e6,Σk<=5e6
平面图有一个性质
|E|≤3×n+6
平面图欧拉定理:一个连通平面图满足
R=|E|−|V|+2
其中
R
是域的个数(包括无穷域),
那么如果平面图不连通
K 为联通块数量。
那么可以类似求拓扑序的方法,每次把当前图中度数最小的点拿出来,求出序列
这样就每次询问就最多只要枚举
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int,int> PAR;
const int N=400010;
int n,m,cnt,icnt,G[N],d[N],iG[N],vis[N];
struct edge{
int t,nx;
}E[N],iE[N];
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void Insert(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt; d[x]++;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt; d[y]++;
}
priority_queue<PAR> Q;
inline void addedge(int x,int y){
iE[++icnt].t=y; iE[icnt].nx=iG[x]; iG[x]=icnt;
}
int q,it,iQ[N],fa[N],ivis[N],a[5000010];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main(){
rea(n); rea(m);
for(int i=1,x,y;i<=m;i++)
rea(x),rea(y),Insert(x,y);
for(int i=1;i<=n;i++)
if(d[i]<=6) Q.push(PAR(-d[i],i));
while(!Q.empty()){
int x=Q.top().second,y=-Q.top().first; Q.pop();
if(d[x]!=y) continue; vis[x]=1;
for(int i=G[x];i;i=E[i].nx)
if(!vis[E[i].t]){
d[E[i].t]--; Q.push(PAR(-d[E[i].t],E[i].t));
addedge(x,E[i].t);
}
}
rea(q);
while(q--){
int V,E=0,L=0,x;
rea(V); it++;
for(int i=1;i<=V;i++)
rea(a[i]),iQ[a[i]]=it,fa[a[i]]=a[i];
for(int k=1;k<=V;k++){
int x=a[k];
for(int i=iG[x];i;i=iE[i].nx)
if(iQ[iE[i].t]==it){
fa[find(x)]=find(iE[i].t);
E++;
}
}
for(int i=1;i<=V;i++)
if(ivis[find(a[i])]!=it) ivis[find(a[i])]=it,L++;
printf("%d\n",E-V+L);
}
return 0;
}