Description
给出一张n个点,m条边的无向联通图,现在你要给每条边一个方向,设f(x)表示x所能到达的点的数量,你需要使得最小的f(x)最大。
求一种方案。
n,m<=4*10^5
Solution
这道题一点都不像F题(毕竟div.2)
首先,处于同一个点双中的点都可以互相到达。
于是先考虑双联通缩点,我们就得到了一棵树。
每个点的点权就是它所在的点双的大小。
现在我们就是要给每条树边一个方向。
毕竟你可以二分,但是还是有更简单的做法。
树嘛~~就有n-1条边,n个点,对不对?
也就是说,我们所有的点的出度和就是n-1?
那么就意味着有一个点一定没有出边!!
如果没有出边的话,那么它的大小就不会改变。
我们要让最小值最大。。。
那么我们就让这个没有出边的点是最大的那个点双就好啦。。
因为其他所有点都可以指向这个点。。。
那么就解决了,构造方案随便写写就好了2333
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
using namespace std;
const int N=4*1e5+5;
int n,m,l,id,tot,root,mx,c[N],x[N],y[N],dfn[N],low[N],d[N];
int last[N],next[N*2],t[N*2],mark[N*2];
bool to[N],bz[N],g[N*2];
void add(int x,int y,int z) {
t[++l]=y;mark[l]=z;next[l]=last[x];last[x]=l;
}
void tarjan(int x) {
dfn[x]=low[x]=++tot;d[tot]=x;bz[x]=1;
rep(i,x) if (!g[i]) {
g[i]=g[i^1]=1;
if (y[mark[i]]!=t[i]) to[mark[i]]=1;
if (!dfn[t[i]]) {
tarjan(t[i]);
low[x]=min(low[x],low[t[i]]);
} else if (bz[t[i]]) low[x]=min(low[x],dfn[t[i]]);
}
if (dfn[x]==low[x]) {
id++;int size=0;
while (d[tot+1]!=x) {
c[d[tot]]=id;size++;
bz[d[tot--]]=0;
}
if (size>mx) mx=size,root=id;
}
}
void dfs(int x,int z) {
rep(i,x) if (t[i]!=z) {
if (c[y[mark[i]]]==t[i]) to[mark[i]]=1;
else to[mark[i]]=0;
dfs(t[i],x);
}
}
int main() {
scanf("%d%d",&n,&m);l=1;
fo(i,1,m) scanf("%d%d",&x[i],&y[i]),add(x[i],y[i],i),add(y[i],x[i],i);
tarjan(1);printf("%d\n",mx);
memset(last,0,sizeof(last));l=0;
fo(i,1,m) if (c[x[i]]!=c[y[i]]) add(c[x[i]],c[y[i]],i),add(c[y[i]],c[x[i]],i);
dfs(root,0);
fo(i,1,m) {
if (to[i]) swap(x[i],y[i]);
printf("%d %d\n",x[i],y[i]);
}
}