[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; }
星星之火,终将成燎原之势