题目:洛谷P1967、Vijos P1843、codevs3287。
题目大意:有n个城市m条道路,每条道路有一个限重,规定货车运货不能超过限重。有一些询问,问你两个城市之间一次最多能运多少重的货(可能无法到达)。
解题思路:首先,要保证原来连通的点连通,限重要尽可能大,所以最大生成树。然后对每个询问找两个点的最近公共祖先,然后求出两点路径上最大限重的最小值即可。
用倍增求LCA,可以边算边求出最小值,不用用一些复杂的方法。代码中我用sml[x][i]表示x和它的第$2^i$个祖先之间的路径上最大限重的最小值。然后在倍增时更新答案即可。详见代码
C++ Code:
#include<cstdio> #include<algorithm> #include<cctype> #include<cstring> #include<cstdio> using std::sort; using std::swap; struct edge{ int u,v,t; bool operator < (const edge& rhs)const{return t>rhs.t;} }e[50005]; struct tree_edge{ int to,dist,nxt; }E[120005]; int n,m,fa[10005],head[10005]={0},cnt=0,ans,deep[10005],p[10005][16],sml[10005][16]; inline int min(int a,int b){return(a<b)?(a):(b);} inline int readint(){ char c=getchar(); int p=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())p=(p<<3)+(p<<1)+(c^'0'); return p; } int dad(int x){return(fa[x]==x)?(x):(fa[x]=dad(fa[x]));} inline int addedge(int from,int to,int dist){ E[++cnt]=(tree_edge){to,dist,head[from]}; head[from]=cnt; E[++cnt]=(tree_edge){from,dist,head[to]}; head[to]=cnt; } void dfs(int u){ for(int i=head[u];i;i=E[i].nxt) if(!deep[E[i].to]){ deep[E[i].to]=deep[u]+1; p[E[i].to][0]=u; sml[E[i].to][0]=E[i].dist; dfs(E[i].to); } } void init(){ for(int j=1;(1<<j)<=n;++j) for(int i=1;i<=n;++i) if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1],sml[i][j]=min(sml[i][j-1],sml[p[i][j-1]][j-1]); } int lca(int x,int y,int& ans){ ans=2000000000; int i; if(deep[x]<deep[y])swap(x,y); for(i=0;(1<<i)<=n;++i);--i; for(int j=i;j>=0;--j) if(deep[p[x][j]]>=deep[y]){ ans=min(ans,sml[x][j]),x=p[x][j]; } if(x==y)return x; for(int j=i;j>=0;--j) if(p[x][j]!=p[y][j]&&p[x][j]!=-1){ ans=min(ans,min(sml[x][j],sml[y][j])); x=p[x][j]; y=p[y][j]; } ans=min(ans,min(sml[x][0],sml[y][0])); return p[x][0]; } int main(){ n=readint(),m=readint(); for(int i=1;i<=m;++i)e[i].u=readint(),e[i].v=readint(),e[i].t=readint(); sort(e+1,e+m+1); for(int i=1;i<=n;++i)fa[i]=i; for(int okE=1,now=1;now<=m;++now){ int a=dad(e[now].u),b=dad(e[now].v); if(a!=b){ fa[b]=a; addedge(e[now].u,e[now].v,e[now].t); ++okE; } if(okE==n)break; } int Q=readint(); memset(deep,0,sizeof deep); memset(p,-1,sizeof p); memset(sml,0x3f,sizeof sml); for(int i=1;i<=n;++i) if(!deep[i]){ deep[i]=1; dfs(i); } init(); while(Q--){ int x=readint(),y=readint(); int a=dad(x),b=dad(y); if(a!=b){ puts("-1"); continue; } lca(x,y,ans); printf("%d ",ans); } }