【noip2013提高组day1T3】 货车运输 RMQ+LCA+倍增+最大生成树

10 篇文章 0 订阅
2 篇文章 0 订阅

P1967 货车运输

数据范围
题目描述

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

输入输出格式

输入格式:
输入文件名为 truck.in。

输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道

路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。意:x 不等于 y,两座城市之间可能有多条道路。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出格式:
输出文件名为 truck.out。

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

车不能到达目的地,输出-1。

输入输出样例

输入样例#1:
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出样例#1:
3
-1
3
说明

对于 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。

这里写图片描述

注意:
1.注意维护limit数组和f数组的时候的顺序
2.可以加入另一个并查集数组判断-1的情况,优化。
3.求最大生成树注意有重边的情况,所以先进行一遍从大到小的排序,先加入的边一定是最优的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100006
#define inf 2147483647
using namespace std;
int e_num,n,m;
int head[N*2];
int father[N],mother[N];
int deep[N],vis[N];
struct node1
{
    int x,y,v;
}love[N];
struct node2
{
    int to,dis,next;
}e[N*2];
struct node3
{
    int c,fa;
}f[N*2][20];
int get()
{
    int x=0,p=1;char c;
    c=getchar();
    while (c<'0'||c>'9') {if (c=='-') p=-1;c=getchar();}
    while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*p;
}
void add(int from,int to,int dis)
{
    ++e_num;
    e[e_num].to=to;
    e[e_num].dis=dis;
    e[e_num].next=head[from];
    head[from]=e_num;
}
bool cmp(node1 a,node1 b)
{
    return a.v>b.v;
}
int find_father(int x)
{
    if (father[x]!=x) father[x]=find_father(father[x]);
    return father[x];
}
void mix_father(int x,int y)
{
    int xx,yy;
    xx=find_father(x);
    yy=find_father(y);
    father[yy]=xx;
}
int find_mother(int x)
{
    if (mother[x]!=x) mother[x]=find_mother(mother[x]);
    return mother[x];
}
void mix_mother(int x,int y)
{
    int xx,yy;
    xx=find_mother(x);
    yy=find_mother(y);
    mother[yy]=xx;
}
void rmq(int t)
{
    int i;
    for (i=1;i<=20;i++)
    {
        if (deep[t]<(1<<i))
            break;
        f[t][i].c=min(f[f[t][i-1].fa][i-1].c,f[t][i-1].c);
        f[t][i].fa=f[f[t][i-1].fa][i-1].fa; 
    }
    vis[t]=true;
    for (i=head[t];i;i=e[i].next)
        if (!vis[e[i].to])
        {
            deep[e[i].to]=deep[t]+1;
            f[e[i].to][0].fa=t;
            f[e[i].to][0].c=e[i].dis;
            rmq(e[i].to);
        }
}
void kruskal()
{
    int i,k=0;
    for (i=1;i<=m;i++)
    {
        if (find_father(love[i].x)==find_father(love[i].y))
           continue;
        mix_father(love[i].x,love[i].y);
        k++;
        add(love[i].x,love[i].y,love[i].v);
        add(love[i].y,love[i].x,love[i].v);
        if (k==n-1) break;
    }
}
int lca(int x,int y)
{
    int i,ans=inf;
    if (deep[x]<deep[y])
    {
        swap(x,y);
    }
    for (i=20;i>=0;i--)
    {
        if (deep[x]-deep[y]>=(1<<i))
        {
            ans=min(f[x][i].c,ans);
            x=f[x][i].fa;   
        }    
    }
    if (x==y) return ans;
    int u=0;
    while (deep[x]>=(1<<u)) u++;
    for (i=u;i>=0;i--)
        if (f[x][i].fa!=f[y][i].fa)
        {
            ans=min(f[x][i].c,ans);
            x=f[x][i].fa;
            ans=min(f[y][i].c,ans);
            y=f[y][i].fa;
        }
    return min(ans,min(f[x][0].c,f[y][0].c));
}
int main()
{
    int x,y,i;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) mother[i]=i;
    for (i=1;i<=m;i++)
    {
        love[i].x=get();love[i].y=get();love[i].v=get();
        mix_mother(love[i].x,love[i].y);
    }
    sort(love+1,love+m+1,cmp);
    for (i=1;i<=n;i++) father[i]=i;
    kruskal();
    rmq(1);
    int q=get();
    for (i=1;i<=q;i++)
    {
        x=get();y=get();
        if (find_mother(x)!=find_mother(y)) {printf("-1\n");continue;}
        printf("%d\n",lca(x,y));
    }
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值