参考
题意:一个有向无环图,其中入度为0的点称为物资提供点,现在有q次操作,每次给出两个点,如果破坏图上的某个点可以使得这两个点中的任何一个无法到达物资提供点则说明破坏成功,问有多少个可以破坏成功的点。
如果我们建一张反图,是不是可以看做从物资点出发到达给定的两个点必须经过的点有哪些。
于是建反图的话==求解有向无环图的必经点问题。
而支配树或者其他的求解必经点的算法都是选定一个点出发走遍所有的图,那我们肯定不能对每个物资点都走一遍,那么可以将这些点都连到一个图以外的点上,从这个点出发走遍全图即可,这种建虚点的思想挺重要的。
我不会支配树…
不过对于一个有向无环图来说,可以通过拓扑排序加lca的方法求解,一个点到起点的必经点就是他的路径深度,如果拓扑序下一个点有多个父亲,那么这些父亲的lca就是该点在支配树上的父亲。
#include<bits/stdc++.h>
using namespace std;
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
const int maxm=4e5+7;
struct Edge{
int v,next;
}edge[maxm<<1];
int head[maxn],headfan[maxn],top;
int fa[maxn][19];
int xxx;
int dep[maxn];
int mi=18;
int du[maxn];
void init(int n){
memset(head,-1,sizeof(head));
memset(headfan,-1,sizeof(headfan));
top=0;
dep[n+1]=1;
}
void add(int u,int v,int head[]){
edge[top].v=v;
edge[top].next=head[u];
head[u]=top++;
}
queue<int> q;
int num;
int t[maxn];
int n;
void topsort(int st){
num=0;
while(!q.empty()) q.pop();
//q.push(st);
for(int i=1;i<=n;++i)
if(du[i]==0)
add(st,i,head),add(i,st,headfan),q.push(i);
int u,v;
while(!q.empty()){
u=q.front(); q.pop();
t[++num]=u;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
--du[v];
if(du[v]==0) q.push(v);
}
}
}
int LCA(int x,int y){
if(x==-1||y==-1) return -1;
if(dep[x]<dep[y]) swap(x,y);
for(int i=mi;i>=0;--i)
if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
for(int i=mi;i>=0;--i)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
int case1;
int m,u,v;
scanf("%d",&case1);
while(case1--){
scanf("%d%d",&n,&m);
init(n);
while(m--){
scanf("%d%d",&u,&v);
add(v,u,head),add(u,v,headfan);
++du[u];
}
topsort(n+1);
int lca;
for(int i=1;i<=num;++i){
u=t[i];
lca=-1;
if(headfan[u]!=-1) lca=edge[headfan[u]].v;
for(int j=headfan[u];j!=-1;j=edge[j].next){
v=edge[j].v;
lca=LCA(lca,v);
}
dep[u]=dep[lca]+1;
fa[u][0]=lca;
//cout<<lca<<endl;
for(int j=1;j<=mi;++j) fa[u][j]=fa[fa[u][j-1]][j-1];
}
int q;
scanf("%d",&q);
while(q--){
scanf("%d%d",&u,&v);
printf("%d\n",dep[u]+dep[v]-dep[LCA(u,v)]-1);
}
for(int i=1;i<=n;++i) dep[i]=0,du[i]=0;
dep[n+1]=0;
}
return 0;
}