codevs 3287||NOIP 2013 货车运输 最大生成树+倍增 解题报告

题目描述 Description

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入描述 Input Description

第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出描述 Output Description

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

样例输入 Sample Input

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

样例输出 Sample Output

3
-1
3

数据范围及提示 Data Size & Hint

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

思路

我刚开始还以为是网络流。。。
先最大生成树建图。
这样就得到了n-1条边链接n个节点 ,再维护两两节点之间的路上最小值
很容易想到LCA 怎么维护呢 开始想想 嗯 树的规模应该不会很大
但是
既然我们能维护i往上2^j 层是谁 我们也可以顺便维护i往上2^j 层路上的最小值
然后 非常愉快的再找lca时顺便更新下答案就ok了
至于-1的情况嘛 如果建完图后不在图里的自然就到不了了
怎么算是不在图里呢 深度为0且不是1

代码

写+调花了一个小时才A。。。

#include
#include
#include
#include
#include
#include
using namespace std;
const int N=50000+5;
const int inf=0x3f3f3f3f;
const int P=20;
int n,m,q,num,head[N],tot,father[N],f[N][P],dep[N],dis[N][P];
struct node
{
    int u,v,w,next;
}ed[N*2];
struct Node
{
    int u,v,w;
}p[N*2];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int cmp(const Node &x,const Node &y)
{
    return x.w>y.w;
}
int getfather(int x)
{
    if (x!=father[x]) father[x]=getfather(father[x]);
    return father[x];
}
void build(int u,int v,int dis)
{
    num++;
    ed[num].u=u;
    ed[num].v=v;
    ed[num].w=dis;
    ed[num].next=head[u];
    head[u]=num;
}
void dfs(int now,int u,int Dis)
{
    f[now][0]=u;dis[now][0]=Dis;
    for (int i=head[now];i!=-1;i=ed[i].next)
    if (ed[i].v!=u) 
    {
        dep[ed[i].v]=dep[now]+1;
        dfs(ed[i].v,now,ed[i].w);
    }
}
int LCA(int a,int b)
{
    if (a!=1&&dep[a]==0) return -1;
    if (b!=1&&dep[b]==0) return -1;
    int ret=inf;
    if (dep[a]int t=dep[a]-dep[b];
    if (t)
    {
        for (int i=0;i<=17;i++)
        if (t&(1<if (a==b)return ret;
    for (int i=17;i>=0;i--)
    if (f[a][i]!=f[b][i])
    {
        ret=min(ret,dis[a][i]);
        ret=min(ret,dis[b][i]);
        a=f[a][i];b=f[b][i];
    }
    ret=min(ret,min(dis[a][0],dis[b][0]));
    return ret;
}
int main()
{
    n=read();m=read();
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    father[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        x=read();y=read();z=read();
        p[i].u=x;p[i].v=y;p[i].w=z;
    }
    sort(p+1,p+1+m,cmp);
    for (int i=1;i<=m;i++)
    {
        int u=p[i].u,v=p[i].v;
        int x=getfather(u),y=getfather(v);
        if (x!=y)
        {
            build(u,v,p[i].w);build(v,u,p[i].w);
            father[y]=x;
            tot++;
            if (tot==n-1) break;
        }
    }
    q=read();
    dep[1]=0;
    memset(dis,127/3,sizeof(dis));
    dfs(1,1,0);
    dis[1][0]=inf;
    for (int j=1;j<=17;j++)
    for (int i=1;i<=n;i++)
    {
        f[i][j]=f[f[i][j-1]][j-1];
        dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);
    }
    for (int i=1;i<=q;i++)
    {
        int x,y;
        x=read();y=read();
        int ans=LCA(x,y);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(————单个题目———,————图论————,生成树,LCA,NOIP)