2014-2015 ACM-ICPC, NEERC L. Useful Roads 支配樹

題目鏈接: 我是鏈接

題意:

一個 2e52e5 個點, 2e52e5條邊的有向圖。我們定義一條簡單路徑爲,沒有一個結點被走過超過一次的路徑。現在我們從結點 11 出發走簡單路徑,如果到達某一個點 xx 的路徑上如果經過 uvu\rightarrow v ,那麼這條路徑要被保留。

現在要你輸出所有要被保留的路徑編號。

做法:

可能題目裏面有點繞,對於一條路徑是否被保留的說法。

其實提取一下就是,對於一條路徑 uvu\rightarrow v 如果到達 uu 之前必定會經過 vv ,即 vvuu 的一個支配點,那麼這條邊就需要被刪去。

這就需要用到支配樹了,事實證明板子很重要。。之前的板子怎麼都過不了,換了一個就過了,對於內部的代碼,需要花很多時間理解,忘記的又很快…就…嗯…

在建出樹之後,對 dfndfn 操作一番就可以了,具體看代碼就好。

代碼

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章