Description
给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).
现在有 K个询问 (1 < = K < = 20,000)。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
Input
第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
Output
对每个询问,输出最长的边最小值是多少。
Sample Input
6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
Sample Output
5
5
5
4
4
7
4
5
5
5
4
4
7
4
5
HINT
1 <= N <= 15,000
1 <= M <= 30,000
1 <= d_j <= 1,000,000,000
1 <= K <= 15,000
题解Here!
在$BZOJ$闲逛的时候发现了这题。
这$TM$不是$NOIP2013\text{货车运输}$嘛。。。
顺手码了。。。
然而这种沙茶题我竟然没有$1A$,真是太失败了。。。
然后发现,我$TM$竟然手抽了,把$will$打成了$f$。。。
手残。。。
所以一发$Kruskal+LCA+\text{树链剖分}$就好了。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) b[x].data
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define MAXN 20010
using namespace std;
int n,m,q,c=1,d=1;
int father[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],top[MAXN];
struct Tree{
int next,to;
}a[MAXN<<1];
struct Segment_Tree{
int data,l,r;
}b[MAXN<<2];
struct Edge{
int u,v,w;
bool used;
}g[MAXN<<1];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline bool cmp(const Edge &p,const Edge &q){return p.w<q.w;}
int find(int x){return father[x]==x?x:father[x]=find(father[x]);}
inline void uniun(int x,int y){x=find(x);y=find(y);if(x!=y)father[y]=x;}
inline void add(int x,int y){
a[c].to=y;a[c].next=head[x];head[x]=c++;
a[c].to=x;a[c].next=head[y];head[y]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
id[rt]=d++;top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])dfs2(will,will);
}
}
inline void pushup(int rt){
DATA(rt)=max(DATA(LSON),DATA(RSON));
}
void buildtree(int l,int r,int rt){
LSIDE(rt)=l;RSIDE(rt)=r;
if(l==r){
DATA(rt)=0;
return;
}
int mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update(int l,int r,int c,int rt){
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
DATA(rt)=c;
return;
}
int mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update(l,r,c,LSON);
if(mid<r)update(l,r,c,RSON);
pushup(rt);
}
int query(int l,int r,int rt){
int ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
int mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans=max(ans,query(l,r,LSON));
if(mid<r)ans=max(ans,query(l,r,RSON));
return ans;
}
void kruskal(){
int s=0;
for(int i=1;i<=m&&s<n-1;i++)
if(find(g[i].u)!=find(g[i].v)){
uniun(g[i].u,g[i].v);
add(g[i].u,g[i].v);
g[i].used=true;
s++;
}
for(int i=1;i<=n;i++)
if(!deep[i]){
deep[i]=1;
dfs1(i);
dfs2(i,i);
}
buildtree(1,n,1);
for(int i=1;i<=m;i++)
if(g[i].used){
if(deep[g[i].u]>deep[g[i].v])swap(g[i].u,g[i].v);
update(id[g[i].v],id[g[i].v],g[i].w,1);
}
}
void solve(int x,int y){
int s=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
s=max(s,query(id[top[x]],id[x],1));
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
if(x!=y)s=max(s,query(id[x]+1,id[y],1));
printf("%d\n",s);
}
void work(){
int x,y;
while(q--){
x=read();y=read();
solve(x,y);
}
}
void init(){
n=read();m=read();q=read();
for(int i=1;i<=m;i++){
g[i].u=read();g[i].v=read();g[i].w=read();
g[i].used=false;
}
for(int i=1;i<=n;i++)father[i]=i;
sort(g+1,g+m+1,cmp);
kruskal();
}
int main(){
init();
work();
return 0;
}