[平面图欧拉定理]ONTAK2015. Ogród zoologiczny

来源:互联网 发布:spring mvc传对象数组 编辑:程序博客网 时间:2024/05/22 07:48

给定n个点m条边的平面图,q个询问,每次询问给出k个点,问这k个点的导出子平面图的域(不包括无穷域)的个数

n<=5e4,m<=2e5,q<=1e6,Σk<=5e6

平面图有一个性质

|E|3×n+6

平面图欧拉定理:一个连通平面图满足

R=|E||V|+2

其中 R 是域的个数(包括无穷域), E 是边集, V 是点集

那么如果平面图不连通

R=|E||V|+K+1

K 为联通块数量。

那么可以类似求拓扑序的方法,每次把当前图中度数最小的点拿出来,求出序列 A,一条 uv 的无向边可以变成一条 uv 的有向边,其中 uA 中的位置小于 vA 中的位置。这就相当于给边重点向。

这样就每次询问就最多只要枚举3n+6条边就可以求出平面图的边集,然后并查集求一下联通块数量就可以了。

#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;}