1. 程式人生 > >tyvj4878 道路修建 雙連通分量+單調佇列

tyvj4878 道路修建 雙連通分量+單調佇列

Description

A國是一個商業高度發達的國家。它包含了n座城市,每座城商業都很發達。但不幸的是,A國的交通並沒有像其商業那麼發達,它僅僅保證了任意兩座城市之間有路徑存在,而且只存在唯一的一條!

擁有雄厚經濟實力的商人們決定集資修建一條路,但在修建方案上各個商人都希望新建成的道路對自己利益最大。最終他們決定造一條路,使得兩個城市間所需經過道路的數量的最大值儘可能小。為此他們提出了很多修建方案,但他們並不知道每一方案新建道路後最遠城市間的最大值為多少,他們有多種修建方案,你能告訴他們每一方案對應的最遠城市間的最大值嗎?

Solution

今天做了一道加強版。。寫了3.8k

首先這一定是環套樹,答案可以是樹上的最長鏈或者從某一葉子出發跨越環結束於某葉子的路徑

先跑連通分量把環摳出來,兩次bfs求出每棵樹上最長鏈。我們記以環上節點x為根的子樹中以x為起點的最長路徑為dis[x],那麼跨過環的答案一定形如dis[x]+dis[y]+get_dis(x,y)這樣。

我們把環上的點複製一份,那麼就可以只考慮順時針的距離。如果邊權為1,下標相減就是兩點的距離。如果邊權不等,那麼字首和就能算環上點的距離

觀察這個柿子。dis[x]+sum[x]是常數,等價於我們要求某一區間內最大的dis[y]-sum[y],這個上單調佇列即可

然後可能會有重邊和自環。這個就離線排序保留最短邊就行了

Code

#include <stdio.h>
#include
<string.h>
#include <algorithm> #include <stack> #include <vector> #include <queue> #include <map> #define rep(i,st,ed) for (register int i=st;i<=ed;++i) #define fill(x,t) memset(x,t,sizeof(x)) typedef long long LL; const int N=2000005; struct edge {int x,y,w,next;
} e[N*2],g[N*2]; int ls[N],fa[N],edCnt=1; int dfn[N],low[N],bel[N]; int a[N],q[N],col[N],yqw; int size[N],whf[N],max,n; LL sum[N],dis[N],lxf[N],wjp[N],ans; std:: stack <int> stack; std:: map <int,bool> map[N]; bool vis[N],inq[N],used[N],flag; inline int read() { int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void add_edge(int x,int y,int w) { e[++edCnt]=(edge) {x,y,w,ls[x]}; ls[x]=edCnt; e[++edCnt]=(edge) {y,x,w,ls[y]}; ls[y]=edCnt; } void dfs1(int now,int fa) { dfn[now]=low[now]=++dfn[0]; vis[now]=true; stack.push(now); for (int i=ls[now];i;i=e[i].next) { if (e[i].y==fa) continue; if (!dfn[e[i].y]) { dfs1(e[i].y,now); low[now]=std:: min(low[now],low[e[i].y]); } else if (vis[e[i].y]) low[now]=std:: min(dfn[e[i].y],low[now]); } if (low[now]==dfn[now]) { int y=0; bel[0]++; while (y!=now) { y=stack.top(); stack.pop(); bel[y]=bel[0]; size[bel[0]]++; vis[y]=false; } } } void dfs2(int now,int fa) { a[++a[0]]=now; if (a[0]==yqw) return (void) (flag=true); for (int i=ls[now];i;i=e[i].next) { if (flag) continue; if (!vis[e[i].y]) continue; if (e[i].y==fa) continue; dfs2(e[i].y,now); } } void dfs3(int now,int c) { col[now]=c; for (int i=ls[now];i;i=e[i].next) { if (col[e[i].y]||vis[e[i].y]) continue; dfs3(e[i].y,c); } } int bfs(int st) { int ret=0; used[st]=true; std:: queue <int> que; que.push(st); dis[st]=0; for (;!que.empty();) { int now=que.front(); que.pop(); if (dis[now]>dis[ret]) ret=now; for (int i=ls[now];i;i=e[i].next) { if (col[e[i].y]==col[st]&&!used[e[i].y]) { dis[e[i].y]=dis[now]+e[i].w; used[e[i].y]=true; que.push(e[i].y); } } } return ret; } bool cmp(edge a,edge b) { if (a.x==b.x&&a.y==b.y) return a.w<b.w; if (a.x==b.x) return a.y<b.y; return a.x<b.x; } int main(void) { freopen("data.in","r",stdin); // freopen("myp.out","w",stdout); n=read(); int st,chp=0; rep(i,1,n) { int x=read(),y=read(),w=read(); if (x>y) std:: swap(x,y); g[i]=(edge) {x,y,w}; } std:: sort(g+1,g+n+1,cmp); rep(i,1,n) { if (g[i].x==g[i].y) { chp=true; continue; } if (g[i].x==g[i-1].x&&g[i].y==g[i-1].y) { chp=true; continue; } add_edge(g[i].x,g[i].y,g[i].w); } if (chp) { int ret=bfs(1); fill(used,0); ans=dis[bfs(ret)]; printf("%lld\n", ans+1); return 0; } dfs1(1,0); rep(i,1,n) if (size[bel[i]]!=1) { st=i; ++yqw; vis[i]=true; } dfs2(st,0); rep(i,1,a[0]) dfs3(a[i],i); rep(i,1,a[0]) a[a[0]+i]=a[i]; fill(used,0); rep(i,1,a[0]) { max=bfs(a[i]); for (int j=ls[a[i]];j;j=e[j].next) { if (e[j].y==a[i+1]) sum[i+1]=sum[i]+e[j].w; } wjp[i]=dis[max]-sum[i]; lxf[i]=dis[max]+sum[i]; } fill(used,0); rep(i,a[0]+1,a[0]*2) { max=bfs(a[i-a[0]]); for (int j=ls[a[i]];j;j=e[j].next) { if (e[j].y==a[i+1]) sum[i+1]=sum[i]+e[j].w; } wjp[i]=dis[max]-sum[i]; lxf[i]=dis[max]+sum[i]; } int h=1,t=1; q[1]=1; rep(i,2,a[0]*2) { while (h<=t&&sum[i]-sum[q[h]]>sum[a[0]+1]/2) h++; if (h<=t) ans=std:: max(ans,lxf[i]+wjp[q[h]]); while (h<=t&&wjp[q[t]]<=wjp[i]) t--; q[++t]=i; } rep(i,1,n) if (size[bel[i]]!=1) { vis[i]=true; } else vis[i]=false; fill(used,0); rep(i,1,a[0]) whf[i]=bfs(a[i]); fill(used,0); rep(i,1,a[0]) { int ret=bfs(whf[i]); ans=std:: max(ans,dis[ret]); } printf("%lld\n", ans+1); return 0; }