题解:
新建
S
S
<script type="math/tex" id="MathJax-Element-22">S</script>点连向所有普通护士。
注意到两个特殊护士能放假的等价条件是支配树上的lca为S,一个普通护士和一个特殊护士不能放假的条件是后者在支配树上位于前者子树中,建出支配树即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(LL x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const int N=1e5+50;
int n,k,S,ind;
int fa[N],anc[N],mnsd[N],sze[N];
int dfn[N],id[N],sdom[N],idom[N];
vector <int> pre[N];
vector <int> buc[N];
vector <int> edge[N];
inline void add(int x,int y) {
edge[x].push_back(y);
pre[y].push_back(x);
}
inline void dfs(int x,int f) {
anc[x]=x; dfn[x]=++ind; id[ind]=x;
sdom[x]=mnsd[x]=x; fa[x]=f;
for(auto v:edge[x]) if(!dfn[v]) dfs(v,x);
}
inline void ga(int x) {
if(anc[x]==x) return;
ga(anc[x]);
mnsd[x]=(dfn[sdom[mnsd[x]]]<dfn[sdom[mnsd[anc[x]]]]) ? mnsd[x] : mnsd[anc[x]];
anc[x]=anc[anc[x]];
}
inline int eval(int x) {return ga(x),mnsd[x];}
inline void find_idom() {
dfs(S,0);
for(int i=ind;i>=2;i--) {
int u=id[i];
for(auto v:pre[u]) {
if(!dfn[v]) continue;
int t=eval(v);
if(dfn[sdom[t]]<dfn[sdom[u]]) sdom[u]=sdom[t];
}
int f=fa[u]; anc[u]=f;
buc[sdom[u]].push_back(u);
for(auto v:buc[f]) {
int t=eval(v);
if(dfn[sdom[t]]<dfn[sdom[v]]) idom[v]=t;
else idom[v]=sdom[v];
}
buc[f].clear();
}
for(int i=2;i<=ind;i++) {
int u=id[i];
if(idom[u]!=sdom[u]) idom[u]=idom[idom[u]];
}
}
int main() {
n=rd(), k=rd(), S=n+1;
for(int i=1;i<=k;i++) sze[i]=1;
for(int i=k+1;i<=n;i++) add(S,i);
for(int i=1;i<=k;i++)
for(int j=rd();j;j--) add(rd(),i);
find_idom(); int j=0;
for(int i=1;i<=k;i++) j+=(!dfn[i]);
W(j); putchar('\n');
for(int i=1;i<=k;i++) if(!dfn[i]) W(i), putchar(' '); if(j) putchar('\n');
for(int i=ind;i>=2;i--) sze[idom[id[i]]]+=sze[id[i]];
LL ans=0, sum=0;
for(int i=ind;i>=2;i--) {
int u=id[i]; if(idom[u]!=S) continue;
ans+=sum*sze[u]; sum+=sze[u];
}
ans=(LL)(k-j)*(k-j-1)/2-ans;
for(int i=2;i<=ind;i++) {
int u=id[i];
if(u>k) ans+=sze[u];
}
W(ans);
}