【noip2013】【BZOJ3732】 货车运输/network [生成树kruskal LCA ]
A国有n座城市,编号从1到n城市之间有m条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有q辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
最大生成树+倍增算路径最小值
最大生成树就是kruskal时将边改为降序 然后就和普通kruskal一样
然后就是用的LCA倍增模板中说的其它骚操作一样
可以在预处理的时候还可以顺便记录下这段路径的权值最大值 最小值或者权值和之类的信息,这样就可以在O(logn)的时间内求出树上两点间路径权值的最大值、最小值还有权值和
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<cmath> #include<stack> #include<algorithm> using namespace std; #define ll long long #define rg register const int N=100000+5,M=500000+5,inf=0x3f3f3f3f,P=19650827; int n,m,q; int dep[N],p[N][25],w[N][25]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } int head[N],tot=0,ans; struct edge{int v,nxt,w;}e[M]; void add(int u,int v,int w){ e[++tot]=(edge){v,head[u],w};head[u]=tot; } int f[N]; struct node{ int u,v,w; }nd[M]; bool cmp(node a,node b){return a.w>b.w;} int find(int x){return f[x]==x?x:f[x]=find(f[x]);} void kruskal(){ int cnt=0; for(rg int i=1;i<=n;++i) f[i]=i; for(rg int i=1,u,v,w;i<=m;++i){ u=nd[i].u,v=nd[i].v,w=nd[i].w; if(find(u)!=find(v)){ f[f[u]]=f[v]; ++cnt; add(u,v,w),add(v,u,w); if(cnt==n-1) break; } } } void dfs(int u){ for(int i=head[u],v;i;i=e[i].nxt){ v=e[i].v; if(!dep[v]){//未走过 dep[v]=dep[u]+1; p[v][0]=u; w[v][0]=e[i].w; dfs(v); } } } void build(){ for(rg int i=1;i<=n;++i){ if(!dep[i]){ dep[i]=1; p[i][0]=0; dfs(i); } } dfs(1);//连起来 for(int i=1; i<=20; i++) for(int j=1; j<=n; j++){ p[j][i]=p[p[j][i-1]][i-1]; w[j][i]=min(w[j][i-1], w[p[j][i-1]][i-1]); } } int LCA(int a,int b){ ans=inf; if(dep[a]>dep[b]) swap(a,b); for(int i=20;i>=0;--i){ if(dep[p[b][i]]<dep[a]) continue; ans=min(ans,w[b][i]);b=p[b][i]; } if(a==b) return ans; for(int i=20;i>=0;--i){ if(p[a][i]==p[b][i]) continue; ans=min(ans,min(w[a][i],w[b][i])); a=p[a][i],b=p[b][i]; } ans=min(ans,min(w[a][0],w[b][0])); return ans; } int main(){ //freopen("in.txt","r",stdin); memset(dep,0,sizeof(dep)); memset(p,0,sizeof(p)); rd(n),rd(m); int u,v,w; for(rg int i=1;i<=m;++i){ rd(u),rd(v),rd(w); nd[i]=(node){u,v,w}; } sort(nd+1,nd+1+m,cmp); kruskal(); build(); rd(q); for(rg int i=1;i<=q;++i){ rd(u),rd(v); if(find(u)!=find(v)) printf("-1\n"); else printf("%d\n",LCA(u,v)); } return 0; }
淦 一样并且还更简单的题我居然打了一晚上我的天
使生成树中任意点A到B的路径上最长边最小
k次询问A到B路径上的最长边长度
#include<bits/stdc++.h> using namespace std; #define ll long long #define Max(X,Y) ((X)>(Y)?(X):(Y)) #define Abs(x) ((x)<0?(-x):(x)) typedef pair<int,int>pii; const int N=15000+5,M=3e4+5,inf=0x3f3f3f3f; int n,m,k; template<class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } struct Edge{ int u,v,w; bool operator<(const Edge&A)const{return w<A.w;} }E[M]; int head[N],tot=0; struct edge{int v,w,nxt;}e[N<<1]; void add(int u,int v,int w){ e[++tot]=(edge){v,w,head[u]},head[u]=tot; } int f[N]; int find(int x){return f[x]==x?x:f[x]=find(f[x]);} void kruskal(){ for(int i=1;i<=n;++i) f[i]=i; for(int i=1,u,v,w;i<=m;++i){ if(tot==(n-1)<<1) return; u=E[i].u,v=E[i].v,w=E[i].w; if(find(u)!=find(v)) f[f[u]]=f[v],add(u,v,w),add(v,u,w); } } int dep[N],fa[N][30],mx[N][30]; void dfs(int u,int ff){ fa[u][0]=ff; for(int i=head[u],v;i;i=e[i].nxt){ v=e[i].v; if(v==ff) continue; dep[v]=dep[u]+1,mx[v][0]=e[i].w,dfs(v,u); } } void build(){ dfs(1,0); for(int i=1;i<=20;++i) for(int j=1;j<=n;++j) fa[j][i]=fa[fa[j][i-1]][i-1], mx[j][i]=Max(mx[fa[j][i-1]][i-1],mx[j][i-1]); } int query(int a,int b){ int ans=0; if(dep[a]>dep[b]) swap(a,b); for(int i=20;i>=0;--i) if(dep[fa[b][i]]>=dep[a]) ans=Max(ans,mx[b][i]),b=fa[b][i]; if(a==b) return ans; for(int i=20;i>=0;--i) if(fa[a][i]!=fa[b][i]) ans=Max(ans,Max(mx[a][i],mx[b][i])),a=fa[a][i],b=fa[b][i]; return Max(ans,Max(mx[a][0],mx[b][0])); } int main(){ freopen("2.in","r",stdin); rd(n),rd(m),rd(k); for(int i=1;i<=m;++i) rd(E[i].u),rd(E[i].v),rd(E[i].w); sort(E+1,E+m+1); kruskal(); memset(dep,0,sizeof(dep)); build(); while(k--){ int xx,yy;rd(xx),rd(yy); printf("%d\n",query(xx,yy)); } return 0; }