題目鏈接: 我是鏈接
題意:
一個 個點, 條邊的有向圖。我們定義一條簡單路徑爲,沒有一個結點被走過超過一次的路徑。現在我們從結點 出發走簡單路徑,如果到達某一個點 的路徑上如果經過 ,那麼這條路徑要被保留。
現在要你輸出所有要被保留的路徑編號。
做法:
可能題目裏面有點繞,對於一條路徑是否被保留的說法。
其實提取一下就是,對於一條路徑 如果到達 之前必定會經過 ,即 是 的一個支配點,那麼這條邊就需要被刪去。
這就需要用到支配樹了,事實證明板子很重要。。之前的板子怎麼都過不了,換了一個就過了,對於內部的代碼,需要花很多時間理解,忘記的又很快…就…嗯…
在建出樹之後,對 操作一番就可以了,具體看代碼就好。
代碼
#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;
}