题意:给定一个有向图,改变其中某些边的方向,它将成为一个有向无环图。现在求一个改变边方向的方案,使得所选边边权的最大值最小。
输出:边权的最小值,被反向的边的个数及编号。
Solution:只要二分把每一条边和预期的 v a l val val 个controllers 作比较,只让大于它的边联通,判断有无环即可(该部分的正确性其他题解已经讲得很清楚了,此不再赘述)。最后用拓扑判断是否使这些边反向即可。但是关于每次判断边是否遍历过,我发现每一篇题解都用 memset 来归零,这样如果范围过大不免导致被卡。所以我们可以采用 t o t tot tot 作为第 t o t tot tot 次二分时的标记,如果 p r e p ≠ t o t pre_{p} \not= tot prep=tot ,就代表这一次没有经历过。同时,我们可以通过 v i s t o vis_{to} visto 的非 0 来判断其有无环。(别忘了清零哦!)这样,我们就省去了每次 memset 的损耗了。
more:如果想要追求极致的话可以尝试离散化取值。(我因为太懒就懒得弄了)
code–>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cctype>
#include <cstring>
#define PT 520
using namespace std;
struct node{
int to, nxt, v;
}e[1000005];
queue <int> que;
int n, m, head[1000005], cnt, l, r, vis[1000005], pre[1000005], tot;
int sum, ans[1000005], ppp, minn = 1023456789, dfn[1000005], id[1000005];
inline void add(int from, int to, int v){
e[++cnt].nxt = head[from];
head[from] = cnt;
e[cnt].to = to;
e[cnt].v = v;
}
inline int dfs(int p, int val){
pre[p] = tot;
vis[p] = 1;
for(int i = head[p]; i; i = e[i].nxt ){
if(e[i].v > val){
if(pre[e[i].to] == tot && !vis[e[i].to ]){
continue;
}
if((pre[e[i].to ] == tot && vis[e[i].to ]) || dfs(e[i].to , val)) return 1;
}
}
vis[p] = 0;
return 0;
}
inline void work(int val){
for(int i = 1; i <= m; i++)
if(e[i].v > val) dfn[e[i].to ]++;
for(int i = 1; i <= n; i++)
if(!dfn[i]) que.push(i);
while(!que.empty()){
int u = que.front();
que.pop();
id[u] = ++sum;
for(int i = head[u]; i; i = e[i].nxt ){
if(e[i].v > val){
dfn[e[i].to ]--;
if(!dfn[e[i].to ]) que.push(e[i].to );
}
}
}
}
int read()
{
int s = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)) {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * f;
}
int main(){
n = read(), m = read();
for(int i = 1; i <= m; i++){
int x = read(), y = read(), z = read();
add(x, y, z);
r = max(r, z);
}
l = 0;
int fl;
while(l < r){
fl = 0;
tot++;
sum = 0;
int mid = (l + r) >> 1;
for(int i = 1; i <= n; i++){
if(pre[i] != tot && dfs(i, mid)){
fl = 1;
break;
}
}
if(!fl){
r = mid;
}
else {
l = mid + 1;
}
}
printf("%d ",r);
sum = 0;
work(r);
for(int i = 1; i <= n; i++){
for(int j = head[i]; j; j = e[j].nxt ){
if(e[j].v <= r){
if(id[e[j].to ] < id[i]){
ans[++ppp] = j;
}
}
}
}
printf("%d\n",ppp);
sort(ans + 1, ans + ppp + 1);
for(int i = 1; i <= ppp; i++)
printf("%d ",ans[i]);
return 0;
}
完结撒 fā ✿✿ヽ(°▽°)ノ✿