E - E CodeForces - 1100Eios
一個n個節點的有向圖,節點標號從1到n,存在m條單向邊。每條單向邊有一個權值,表明翻轉其方向所需的代價。求使圖變成無環圖,其中翻轉的最大邊權值最小的方案,以及該方案翻轉的最大的邊權。git
Input 單組輸入,第一行包含兩個整數n和m(2≤n≤100 000,1≤m≤100 000) 接下來m行,每行3個整數,u_i ,v_i
,w_i (1<= u_i , v_i <= n, 1<= w_i <=
10^9),表示u到v有一條權值爲w的道路。道路編號從1開始。沒有自環。spaOutput 在第一行中輸出兩個整數,即要翻轉的最大的邊權,和須要反轉道路數量k。k不須要是最小的。code
在下一行輸出k個由空格分隔的整數,表示須要翻轉的道路編號blog
若是有許多解決方案,請打印其中任何一個。排序
Examples Input 5 6 2 1 1 5 2 6 2 3 2 3 4 3 4 5 5 1 5 4 Output 2 2 1 3 Input 5 7 2 1 5 3 2 3 1 3 3 2 4 1 4 3 5 5 4 1 1 5 3 Output 3 3 3 4 7
#include<iostream> #include<cmath> #include<cstdio> #include<queue> #include<cstring> #define int long long #define inf 10000000000000 using namespace std; int read(){ int res=0;char ch=0; while (!isdigit(ch))ch=getchar(); while (isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return res; } const int N=1000100; struct EDGE{ int ver,nxt,dis,pre; }edge[N]; int n,m,cnt,head[N],vis[N],d[N],ans[N],dfn[N],dfs_cnt; void add(int u,int v,int t){ edge[++cnt].ver=v; edge[cnt].nxt=head[u]; edge[cnt].dis=t; edge[cnt].pre=u; head[u]=cnt; } queue<int>q; bool check(int x){ memset(d,0,sizeof(d));memset(vis,0,sizeof(vis)); for (int i=1;i<=m;i++)if(edge[i].dis>x)d[edge[i].ver]++; for (int i=1;i<=n;i++)if (!d[i])q.push(i); while (!q.empty()){ int u=q.front();q.pop(); for (int i=head[u];i;i=edge[i].nxt) { if (edge[i].dis<=x)continue; int v=edge[i].ver;d[v]--;if (!d[v])q.push(v); } } for (int i=1;i<=n;i++)if (d[i])return 0; return 1; } void solute(int x){ memset(d,0,sizeof(d));memset(vis,0,sizeof(vis)); for (int i=1;i<=m;i++)if(edge[i].dis>x)d[edge[i].ver]++; for (int i=1;i<=n;i++)if (!d[i])q.push(i); while (!q.empty()) { int u=q.front();q.pop();dfn[u]=++dfs_cnt; for (int i=head[u];i;i=edge[i].nxt) { if (edge[i].dis<=x)continue; int v=edge[i].ver;d[v]--;if (!d[v])q.push(v); } } for (int i=1;i<=m;i++){ if (edge[i].dis<=x){ int u=edge[i].pre,v = edge[i].ver; if (dfn[u]>dfn[v])ans[++cnt]=i; } } } signed main(){ n=read();m=read(); for (int i=1;i<=m;i++){ int x=read(),y=read(),t=read();add(x,y,t); } int l=0,r=inf; while (l<r) { int mid=l+r>>1; if (check(mid)) r=mid; else l=mid+1; } cnt=0; solute(r); printf("%lld %lld\n",r,cnt); for (int i=1;i<=cnt;i++){ printf("%lld ",ans[i]); } }