习题:Ralph and Mushrooms(拓扑)
题目
思路
考虑环的一个性质,如果强行断一条边,再跑拓扑,那么对于这条链上一定有\(id_u<id_v\),其中v的深度比u大
对于断的那条边的两个节点,一定有\(id_u>id_v\)
对于题目本身而言,单调性是显然的
考虑二分一个分界点mid,把边权>=mid的建图,如果满足题意,那么一定是一个DAG,通过二分,我们就可以求出最小的最大值
再者考虑构造,构造其实就按照上面提到的环的性质进行构造即可
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
namespace IO
{
void read(int &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void write(int x)
{
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
}
using namespace IO;
struct edge
{
int u,v,w;
}a[100005];
struct node
{
int e;
int w;
};
int n,m;
int l=0,r=1000000001,mid,cnt,tot;
int d[100005];
int id[100005];
bool used[100005];
queue<int> q;
vector<node> g[100005];
vector<int> dag[100005];
void build(int cnt)
{
for(int i=1;i<=n;i++)
dag[i].clear();
for(int i=1;i<=n;i++)
{
d[i]=0;
for(int j=0;j<g[i].size();j++)
{
if(g[i][j].w>=cnt)
{
dag[g[i][j].e].push_back(i);
d[i]++;
}
}
}
}
bool topsort()
{
cnt=0;
for(int i=1;i<=n;i++)
{
used[i]=0;
if(d[i]==0)
q.push(i);
}
while(!q.empty())
{
int t=q.front();
id[t]=++cnt;
q.pop();
used[t]=1;
for(int i=0;i<dag[t].size();i++)
{
int v=dag[t][i];
d[v]--;
if(d[v]==0)
q.push(v);
}
}
for(int i=1;i<=n;i++)
if(used[i]==0)
return 0;
return 1;
}
bool check(int cnt)
{
build(cnt);
return topsort();
}
int main()
{
read(n);read(m);
for(int i=1,u,v,w;i<=m;i++)
{
read(u);read(v);read(w);
a[i].u=u;a[i].v=v;a[i].w=w;
g[u].push_back((node){v,w});
}
while(l+1<r)
{
mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid;
}
while(check(r-1)&&r-1>=1)
r--;
check(r);
write(r-1);putchar(' ');
for(int i=1;i<=m;i++)
if(id[a[i].u]<id[a[i].v])
tot++;
write(tot);
putchar('\n');
for(int i=1;i<=m;i++)
if(id[a[i].u]<id[a[i].v])
{
write(i);
putchar(' ');
}
return 0;
}