[CF 732F]Tourist Reform

来源:互联网 发布:激战2女夏尔捏脸数据 编辑:程序博客网 时间:2024/06/08 02:02

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]);    }}
0 0
原创粉丝点击