星星之火

[JZOJ 5465] [NOIP2017提高A组冲刺11.9] 道路重建 解题报告 (e-dcc+树的直径)

题目链接:

http://172.16.0.132/senior/#main/show/5465

题目:

小X所居住的X国共有n个城市,有m条无向道路将其连接。作为一个统一的国家,X 城的任意两个城市都可以相互到达。
由于X国正处于地震带上,有时X国中会有至多一条道路发生毁坏,无法使用。如果这条道路的毁坏恰好阻断了某些城市的往来,那么我们称这条道路是危险的。
人们并不喜欢危险的道路,于是人们决定重建恰好一条道路,以减少危险的道路数。请告诉人们,重建恰好一条道路后,危险的道路数最少是多少。

题解:

显然在一个边双里,任意删掉一条边依旧是连通的,也就是说危险的道路其实就是桥

因此我们缩边双,建新图

注意到缩掉所有的边双之后图会变成一棵树,我们就是要在这棵树连边,使得上形成的环最大,环上的边本来是危险的,现在不危险了

显然我们要连的是直径的两个端点,求一遍树的直径就好了

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<time.h>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;

const int N=2e5+15;
const int M=1e6+15;
int n,m,tot1,tot2,tim,tp,mx,pos;
int h1[N],h2[N],dfn[N],vis[N],belong[N],low[N];
bool brige[M<<1];
struct E{
    int to,nxt;
}e1[M<<1],e2[M<<1];
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    char ch=nc();int s=0,f=1;
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=nc();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=nc();}
    return s*f;
}
void link1(int u,int v){e1[++tot1]=(E){v,h1[u]};h1[u]=tot1;}
void link2(int u,int v){e2[++tot2]=(E){v,h2[u]};h2[u]=tot2;}
void chkmin(int &x,int y){if (y<x) x=y;}
void init(){
    mem(h1,0);mem(h2,0);mem(dfn,0);mem(low,0);mem(brige,0);
    tot1=tot2=1;
    tim=tp=0;
}
void tarjan(int x,int pre){
    dfn[x]=low[x]=++tim;
    for (int i=h1[x];i;i=e1[i].nxt){
        int y=e1[i].to;
        if (!dfn[y]){
            tarjan(y,i);
            chkmin(low[x],low[y]);
            if (low[y]>dfn[x]) brige[i]=brige[i^1]=1;
        }
        else if (i!=(pre^1)) chkmin(low[x],dfn[y]);
    }
}
void dfs(int x,int edcc){
    belong[x]=edcc;vis[x]=1;
    for (int i=h1[x],y;i;i=e1[i].nxt){
        if (vis[y=e1[i].to]||brige[i]) continue;
        dfs(y,edcc);
    }
}
void dfs1(int x,int len,int pre){
    if (len>mx) mx=len,pos=x;
    for (int i=h2[x],y;i;i=e2[i].nxt){
        if ((y=e2[i].to)==pre) continue;
        dfs1(y,len+1,x);
    }
}
int main(){
    freopen("rebuild.in","r",stdin);
    freopen("rebuild.out","w",stdout);
    while (1)
    {
        n=read();m=read();
        if (!n&&!m) break;
        init();
        for (int i=1,u,v;i<=m;i++){
            u=read();v=read();link1(u,v);link1(v,u);
        }
        tarjan(1,-1);
        mem(vis,0);
        int cnt=0;
        for (int i=1;i<=n;i++) if (!vis[i]) dfs(i,++cnt);
        for (int x=1;x<=n;x++)
            for (int i=h1[x];i;i=e1[i].nxt){
                int y=e1[i].to;
                if (belong[x]==belong[y]) continue;
                link2(belong[x],belong[y]);
            }
        mx=0;
        dfs1(1,1,-1);
        mx=0;
        dfs1(pos,1,-1);
        printf("%d\n",cnt-mx);
    }
    return 0;
}

 

posted @ 2018-10-17 17:11  星星之火OIer  阅读(281)  评论(0编辑  收藏  举报