题目链接: 我是链接
题意:
一个 个点, 条边的有向图。我们定义一条简单路径为,没有一个结点被走过超过一次的路径。现在我们从结点 出发走简单路径,如果到达某一个点 的路径上如果经过 ,那么这条路径要被保留。
现在要你输出所有要被保留的路径编号。
做法:
可能题目里面有点绕,对于一条路径是否被保留的说法。
其实提取一下就是,对于一条路径 如果到达 之前必定会经过 ,即 是 的一个支配点,那么这条边就需要被删去。
这就需要用到支配树了,事实证明板子很重要。。之前的板子怎么都过不了,换了一个就过了,对于内部的代码,需要花很多时间理解,忘记的又很快…就…嗯…
在建出树之后,对 操作一番就可以了,具体看代码就好。
代码
#include<bits/stdc++.h>
#define pb push_back
#define SZ(a) (int)(a.size())
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
using namespace std;
typedef long long ll;
typedef vector<int> vi;
const int maxn=200005;
const int N=200005;
const int maxm=400005;
int n,m,dfn[maxn],tot,End[maxn];
struct edge{
int from,to,flag;
}e[maxm];
struct DominatorTree{ //INDEXADO DE 1=SOURCE
vi g[N],tree[N],rg[N],bucket[N];
int sdom[N],par[N],dom[N],dsu[N],label[N];
int arr[N],rev[N],T=0;
void add(int u,int v){
g[u].push_back(v);
}
void init(int n){
for(int i=0;i<=n;i++){
tree[i].clear(); g[i].clear(); rg[i].clear(); bucket[i].clear();
sdom[i]=0;par[i]=0;dom[i]=0;dsu[i]=0;label[i]=0;
arr[i]=0;rev[i]=0;
}
T=0;
}
int Find(int u,int x=0){
if(u==dsu[u])return x?-1:u;
int v = Find(dsu[u],x+1);
if(v<0)return u;
if(sdom[label[dsu[u]]] < sdom[label[u]])
label[u] = label[dsu[u]];
dsu[u] = v;
return x?v:label[u];
}
void Union(int u,int v){ //Add an edge u-->v
dsu[v]=u; //yup,its correct :)
}
void dfs0(int u){
T++;arr[u]=T;rev[T]=u;
label[T]=T;sdom[T]=T;dsu[T]=T;
for(int i=0;i<SZ(g[u]);i++){
int w = g[u][i];
if(!arr[w])dfs0(w),par[arr[w]]=arr[u];
rg[arr[w]].pb(arr[u]);
}
}
void build(){
dfs0(1);
for(int i=T;i>=1;i--){
for(int j=0;j<SZ(rg[i]);j++){
sdom[i] = min(sdom[i],sdom[Find(rg[i][j])]);
}
if(i>1)bucket[sdom[i]].pb(i);
for(int j=0;j<SZ(bucket[i]);j++){
int w = bucket[i][j];
int v = Find(w);
if(sdom[v]==sdom[w])dom[w]=sdom[w];
else dom[w] = v;
}
if(i>1)Union(par[i],i);
}
for(int i=2;i<=T;i++){
if(dom[i]!=sdom[i]){
dom[i]=dom[dom[i]];
}
tree[rev[i]].pb(rev[dom[i]]);
tree[rev[dom[i]]].pb(rev[i]);
}
}
};
DominatorTree DT;
void dfss(int u,int f){
dfn[u]=++tot;
for(auto v:DT.tree[u]){
if(v==f) continue;
dfss(v,u);
}
End[u]=tot;
}
int main(){
while(~scanf("%d%d",&n,&m)){
DT.init(n);
rep(i,1,m){
int x,y; scanf("%d%d",&x,&y);
e[i]=edge{x,y,0};
DT.add(x,y);
}
DT.build();
tot=0;
for(int i=1;i<=n;i++) dfn[i]=End[i]=0;
dfss(1,-1); int sum=0;
for(int i=1;i<=m;i++){
int u=e[i].from,v=e[i].to;
if(!dfn[u]||!dfn[v]) continue;
if(dfn[u]>dfn[v]&&dfn[u]<=End[v]) continue;
e[i].flag=1; sum++;
}
printf("%d\n",sum);
rep(i,1,m){
if(e[i].flag) printf("%d ",i);
}
printf("\n");
}
return 0;
}