bzoj3732

给你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

Sample Output

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

模拟一下样例,发现最小生成树贼有道理
然后倍增求树上最大值,感觉树剖也行
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 15005
#define maxm 30005
using namespace std;
struct note{
    int u,v,c;
    friend bool operator<(note a,note b)
    {
        return a.c<b.c;
    }
}edge[maxm];
int to[maxm<<1],head[maxn],val[maxm<<1],next[maxm<<1];
int f[maxn][20],g[maxn][20],dep[maxn];
int rep[maxn];
int num,cnt,n,m,k;
int getrep(int x)
{
    if(rep[x]==x) return x;
    return rep[x]=getrep(rep[x]);
}
void dfs(int u,int fa)
{
    for(int edge=head[u];edge;edge=next[edge])
    {
        if(to[edge]==fa) continue;
        f[to[edge]][0]=u;
        g[to[edge]][0]=val[edge];
        dep[to[edge]]=dep[u]+1;
        dfs(to[edge],u);
    }
}
void go_up(int &x,int c)
{
    c=-c;
    for(int i=0;i<=19;i++)
    if(c&(1<<i)) cnt=max(cnt,g[x][i]),x=f[x][i];
}
void make_lca()
{
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
        {
            if(f[i][j-1])
            { 
                f[i][j]=f[f[i][j-1]][j-1];
                g[i][j]=max(g[i][j-1],g[f[i][j-1]][j-1]);
            }
            else f[i][j]=0;
        }    
}
int lca(int x,int y)
{
    if(dep[x]>dep[y]) go_up(x,dep[y]-dep[x]);
    else go_up(y,dep[x]-dep[y]);
    if(x==y) return cnt;
    for(int i=19;i>=0;i--)
    if(f[x][i]!=f[y][i])
    {
        cnt=max(cnt,max(g[x][i],g[y][i])); 
        x=f[x][i];y=f[y][i];   
     } 
     return max(cnt,max(g[x][0],g[y][0]));  
}
void add(int u,int v,int c)
{
    to[++num]=v;
    val[num]=c;
    next[num]=head[u];
    head[u]=num;
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].c);
    }
    sort(edge+1,edge+1+m);
    for(int i=1;i<=n;i++) rep[i]=i;
    for(int i=1;i<=m;i++)
    if(getrep(edge[i].u)!=getrep(edge[i].v))
    {
        rep[getrep(edge[i].u)]=getrep(edge[i].v);
        add(edge[i].u,edge[i].v,edge[i].c);
        add(edge[i].v,edge[i].u,edge[i].c);        
    }
    
    dfs(1,0);
    make_lca();
    while(k--)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        cnt=0;
        printf("%d\n",lca(x,y));
    }
    return 0;
} 

 

posted @ 2017-10-21 18:37  dancer16  阅读(230)  评论(0编辑  收藏  举报
描述