【NOIP2013】货车运输
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P1967
好坑啊!算了,还是怪我LCA写的不熟,沙茶一般把j<maxb写成(1<<j)<maxb。。。
首先,我们可以生成一下最大生成树,保证每个点都连通的情况下,每条路的限重尽量大。但是注意点并不一定都连通,因此我们需要建立多棵最大生成树。然后我们的任务就是查询两点间路径上的最小边权,暴力的话复杂度难以接受,这是我们就可以使用一种较好的方法——倍增。说白了,就是在求LCA的同时维护路径上的最小边权。初始化时,mine[i][0]=w[i][fan[i][0]];然后有mine[i][j]=min(mine[i][j-1],mine[fan[i][j-1]][j-1])。再就是建树的过程容易出错,应该注意。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 inline int min(int a,int b) {return a<b?a:b;} 7 inline void swap(int& a,int& b) {int t=a;a=b;b=t;} 8 inline int get_num() { 9 int num;char c; 10 while((c=getchar())=='\n'||c==' '||c=='\r'); 11 num=c-'0'; 12 while(isdigit(c=getchar())) num=num*10+c-'0'; 13 return num; 14 } 15 void put_num(int i) { 16 if(i<0) putchar('-'),i=-i; 17 if(i>9) put_num(i/10); 18 putchar(i%10+'0'); 19 } 20 const int maxn=1e4+5,maxm=5e4+5,maxb=15,inf=0x3f3f3f3f; 21 struct Edge { 22 int u,v,w; 23 bool operator < (const Edge& rhs) const { 24 return w>rhs.w; 25 } 26 } edge[maxm]; 27 int fa[maxn],d[maxn],fan[maxn][maxb],mine[maxn][maxb]; 28 int f(int i) { 29 if(i==fa[i]) return i; 30 else return fa[i]=f(fa[i]); 31 } 32 int dfs(int v) { 33 if(d[v]) return d[v]; 34 if(f(v)) return d[v]=dfs(fan[v][0])+1; 35 else return 1; 36 } 37 int query(int x,int y) { 38 if(d[x]<d[y]) swap(x,y); 39 int i,j,mmin=inf; 40 for(i=0;(1<<i)<=d[x];++i); 41 --i; 42 for(j=i;j>=0;--j) 43 if(d[x]-(1<<j)>=d[y]) 44 mmin=min(mmin,mine[x][j]),x=fan[x][j]; 45 if(x==y) return mmin; 46 for(j=i;j>=0;--j) 47 if(fan[x][j]!=fan[y][j]) { 48 mmin=min(mmin,min(mine[x][j],mine[y][j])); 49 x=fan[x][j],y=fan[y][j]; 50 } 51 return min(mmin,min(mine[x][0],mine[y][0])); 52 } 53 int main() { 54 int n,m,x,y,z,cnt=0; 55 n=get_num();m=get_num(); 56 for(int i=1;i<=m;++i) { 57 x=get_num();y=get_num();z=get_num(); 58 edge[i].u=x,edge[i].v=y,edge[i].w=z; 59 } 60 sort(edge+1,edge+m+1); 61 for(int i=1;i<=n;++i) fa[i]=i; 62 memset(mine,inf,sizeof(mine)); 63 for(int i=1;i<=m&&cnt<n-1;++i) { 64 int u=f(edge[i].u),v=f(edge[i].v),w=edge[i].w; 65 if(u!=v) fa[v]=u,fan[v][0]=u,mine[v][0]=w,++cnt; 66 } 67 for(int i=1;i<=n;++i) { 68 int root=f(i); 69 d[root]=1; 70 if(!d[i]) dfs(i); 71 } 72 for(int j=1;j<maxb;++j) 73 for(int i=1;i<=n;++i) { 74 fan[i][j]=fan[fan[i][j-1]][j-1]; 75 mine[i][j]=min(mine[i][j-1],mine[fan[i][j-1]][j-1]); 76 } 77 int q=get_num(),first=1; 78 for(int i=1;i<=q;++i) { 79 x=get_num();y=get_num(); 80 if(first) first=0; 81 else putchar('\n'); 82 if(f(x)!=f(y)) put_num(-1); 83 else put_num(query(x,y)); 84 } 85 return 0; 86 }