题目链接:https://codeforces.com/contest/1100/problem/E
题意:给出 n 个点 m 条边的有向图,要翻转一些边,使得有向图中不存在环,问翻转的边中最大权值最小是多少。
题解:首先要二分权值,假设当前最大权值是 w,那么大于 w 的边一定不能翻转,所以大于 w 所组成的有向图不能有环,而剩下小于等于 w 的边一定可以构造出一个没有环的图(因为如果一条边正反插入都形成环的话,那么图里之前已经有环了),构造方法是把大于 w 的边跑拓扑序,然后小于等于 w 的边序号小的连向序号大的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned long long 5 #define mst(a,b) memset((a),(b),sizeof(a)) 6 #define mp(a,b) make_pair(a,b) 7 #define pi acos(-1) 8 #define pii pair<int,int> 9 #define pb push_back 10 #define lowbit(x) ((x)&(-x)) 11 const int INF = 0x3f3f3f3f; 12 const double eps = 1e-6; 13 const int maxn = 1e5 + 10; 14 const int maxm = 1e6 + 10; 15 const ll mod = 1e9 + 7; 16 17 int n,m; 18 19 struct edge { 20 int from,to,w; 21 }e[maxn]; 22 23 vector<int>vec[maxn]; 24 int vis[maxn]; 25 bool flag; 26 27 void dfs(int u,int mid) { 28 vis[u] = 1; 29 for(int i = 0; i < vec[u].size(); i++) { 30 int x = vec[u][i]; 31 if(e[x].w <= mid) continue; 32 if(vis[e[x].to] == 1) { 33 flag = false; 34 continue; 35 } else if(vis[e[x].to] == 2) continue; 36 dfs(e[x].to,mid); 37 } 38 vis[u] = 2; 39 } 40 41 bool check(int mid) { 42 mst(vis, 0); 43 flag = true; 44 for(int i = 1; i <= n; i++) { 45 if(vis[i] == 0) dfs(i,mid); 46 } 47 return flag; 48 } 49 50 vector<int>out; 51 int top[maxn], du[maxn]; 52 53 int main() { 54 #ifdef local 55 freopen("data.txt", "r", stdin); 56 // freopen("data.txt", "w", stdout); 57 #endif 58 scanf("%d%d",&n,&m); 59 for(int i = 1; i <= m; i++) { 60 scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w); 61 vec[e[i].from].push_back(i); 62 } 63 int l = 0, r = 1e9, ans = 0; 64 while(l <= r) { 65 int mid = (l + r) >> 1; 66 if(check(mid)) ans = mid, r = mid - 1; 67 else l = mid + 1; 68 } 69 for(int i = 1; i <= m; i++) 70 if(e[i].w > ans) du[e[i].to]++; 71 queue<int>q; 72 int tot = 0; 73 for(int i = 1; i <= n; i++) 74 if(du[i] == 0) q.push(i); 75 while(!q.empty()) { 76 int u = q.front(); 77 q.pop(); 78 top[u] = ++tot; 79 for(int i = 0; i < vec[u].size(); i++) { 80 int v = vec[u][i]; 81 if(e[v].w <= ans) continue; 82 du[e[v].to]--; 83 if(du[e[v].to] == 0) q.push(e[v].to); 84 } 85 } 86 for(int i = 1; i <= m; i++) 87 if(e[i].w <= ans && top[e[i].from] > top[e[i].to]) out.push_back(i); 88 printf("%d %d ",ans,out.size()); 89 for(int i = 0; i < out.size(); i++) printf("%d ",out[i]); 90 return 0; 91 }