【noip2013】货车运输
题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
输出
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
样例输入
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
样例输出
3
-1
3
题解
解1:kruskal重构树。这道题是求最大生成树,注意还可能是森林。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=200000+50; int n,m,q,fat[maxn],cnt,aa,bb; int fir[maxn],to[maxn],nex[maxn],ecnt; int val[maxn],dep[maxn],sz[maxn],son[maxn],fa[maxn],top[maxn]; bool p[maxn]; struct node{int x,y,z;}a[maxn]; int cmp(const node &a,const node &b){ return a.z>b.z; } void add_edge(int u,int v){ nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v; } template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int father(int x){ if(x!=fat[x]) fat[x]=father(fat[x]); return fat[x]; } void dfs1(int x,int f,int deep){ fa[x]=f; dep[x]=deep; sz[x]=1; p[x]=true; int maxson=-1; for(int e=fir[x];e;e=nex[e]){ int v=to[e]; if(v==f) continue; dfs1(v,x,deep+1); sz[x]+=sz[v]; if(sz[v]>maxson) maxson=sz[v],son[x]=v; } } void dfs2(int x,int topf){ top[x]=topf; if(!son[x]) return ; dfs2(son[x],topf); for(int e=fir[x];e;e=nex[e]){ int v=to[e]; if(v==fa[x]||v==son[x]) continue; dfs2(v,v); } } void kruskal(){ for(int i=1;i<m;i++){ int fa=father(a[i].x),fb=father(a[i].y); if(fa!=fb){ val[++cnt]=a[i].z; fat[fa]=fat[fb]=fat[cnt]=cnt; add_edge(fa,cnt);add_edge(cnt,fa); add_edge(fb,cnt);add_edge(cnt,fb); } } for(int i=1;i<=cnt;i++) if(!p[i]){ int f=father(i); dfs1(f,0,1);dfs2(f,f); } } int lca(int x,int y){ int f1=top[x],f2=top[y]; while(f1!=f2){ if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y); x=fa[f1];f1=top[x]; } return dep[x]<dep[y]?x:y; } int main(){ memset(p,false,sizeof(p)); read(n),read(m);cnt=n; for(int i=1;i<=n;i++) fat[i]=i; for(int i=1;i<=m;i++) read(a[i].x),read(a[i].y),read(a[i].z); sort(a+1,a+1+m,cmp); kruskal(); read(q); while(q--){ read(aa),read(bb); if(father(aa)!=father(bb)){ cout<<-1<<endl;continue; } cout<<val[lca(aa,bb)]<<endl; } return 0; }
解2:树剖,因为 q 和 n 不是太大,O(qlog2n) 的复杂度是可以接受的。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=10000+50; const int maxm=50000*2+50; const int inf=2e9; int n,m,q,fat[maxn],val[maxn],cnt; int fir[maxn],nex[maxm],to[maxm],wi[maxm],ecnt; int top[maxn],dep[maxn],sz[maxn],fa[maxn],son[maxn],id[maxn],wt[maxn]; bool vis[maxn],u[maxn]; struct Road{int x,y,z;}a[maxm]; int cmp(const Road &a,const Road &b){return a.z>b.z;} struct SegmentTree{int l,r,mn;}st[maxn<<2]; void add(int u,int v,int w){ nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;wi[ecnt]=w; } int father(int x){ if(x!=fat[x]) fat[x]=father(fat[x]); return fat[x]; } void un(int x,int y){ int fa=father(x),fb=father(y); if(fa!=fb) fat[fa]=fb; } void kruskal(){ int k=0; sort(a+1,a+1+m,cmp); for(int i=1;i<=m;i++){ int fa=father(a[i].x),fb=father(a[i].y); if(fa!=fb){ un(fa,fb);k++; add(a[i].x,a[i].y,a[i].z); add(a[i].y,a[i].x,a[i].z); } if(k==n-1) break; } } void dfs1(int x,int f,int deep){ fa[x]=f; dep[x]=deep; sz[x]=1; vis[x]=true; for(int e=fir[x];e;e=nex[e]){ int v=to[e]; if(v==f) continue; un(x,v); val[v]=wi[e]; dfs1(v,x,deep+1); sz[x]+=sz[v]; if(sz[v]>sz[son[x]]) son[x]=v; } } void dfs2(int x,int topf){ top[x]=topf; id[x]=++cnt; wt[cnt]=val[x]; if(!son[x]) return ; dfs2(son[x],topf); for(int e=fir[x];e;e=nex[e]){ int v=to[e]; if(v==fa[x]||v==son[x]) continue; dfs2(v,v); } } void pushup(int root){ st[root].mn=min(st[root<<1].mn,st[root<<1|1].mn); } void build(int root,int l,int r){ st[root].l=l;st[root].r=r; if(l==r) st[root].mn=wt[l]; else{ int m=l+r>>1; build(root<<1,l,m);build(root<<1|1,m+1,r); pushup(root); } } int query(int root,int l,int r){ if(st[root].l>r||st[root].r<l) return inf; if(st[root].l>=l&&st[root].r<=r) return st[root].mn; return min(query(root<<1,l,r),query(root<<1|1,l,r)); } int Qry(int x,int y){ int f1=top[x],f2=top[y],ans=inf; while(f1!=f2){ if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2); ans=min(ans,query(1,id[f1],id[x])); x=fa[f1];f1=top[x]; } if(dep[x]>dep[y]) swap(x,y); ans=min(ans,query(1,id[x]+1,id[y])); return ans; } template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main(){ memset(u,false,sizeof(u)); read(n),read(m); for(int i=1;i<=n;i++) fat[i]=i; for(int i=1;i<=m;i++) read(a[i].x),read(a[i].y),read(a[i].z); kruskal(); for(int i=1;i<=n;i++) fat[i]=i; memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++) if(!vis[i]){ dfs1(i,0,1);dfs2(i,i);u[id[i]]=true; } build(1,1,n); read(q); while(q--){ int x,y; read(x),read(y); int ans=Qry(x,y); if(father(x)!=father(y)) printf("-1\n"); else printf("%d\n",ans); } return 0; }