zoukankan      html  css  js  c++  java
  • JDOJ 1062 过路费

    JDOJ 1062 过路费

    JDOJ传送门

    Description

    在某个遥远的国家里,有n个城市。编号为1,2,3,…,n。这个国家的政府修建了m条双向道路,每条道路连接着两个城市。政府规定从城市S到城市T需要收取的过路费为所经过城市之间道路长度的最大值。如:A到B长度为2,B到C长度为3,那么开车从A经过B到C需要上交的过路费为3。

    佳佳是个做生意的人,需要经常开车从任意一个城市到另外一个城市,因此他需要频繁地上交过路费,由于忙于做生意,所以他无时间来寻找交过路费最低的行驶路线。然而,当他交的过路费越多他的心情就变得越糟糕。作为秘书的你,需要每次根据老板的起止城市,提供给他从开始城市到达目的城市,最少需要上交多少过路费。

    Input

    ​ 第一行是两个整数n 和m,分别表示城市的个数以及道路的条数。
      接下来m行,每行包含三个整数 a,b,w(1≤a,b≤n,0≤w≤10^9),表示a与b之间有一条长度为w的道路。
      接着有一行为一个整数q,表示佳佳发出的询问个数。
      再接下来q行,每一行包含两个整数S,T(1≤S,T≤n,S≠T), 表示开始城市S和目的城市T。

    Output

    输出文件共q行,每行一个整数,分别表示每个询问需要上交的最少过路费用。输入数据保证所有的城市都是连通的。

    Sample Input

    4 5 1 2 10 1 3 20 1 4 100 2 4 30 3 4 10 2 1 4 4 1

    Sample Output

    20 20

    HINT

    对于30%的数据,满足1≤ n≤1000,1≤m≤10000,1≤q≤100;

    对于50%的数据,满足1≤ n≤10000,1≤m≤10000,1≤q≤10000;
      对于100%的数据,满足1≤ n≤10000,1≤m≤100000,1≤q≤10000;


    题解:

    和NOIP 2013 货车运输的这道题很像。

    一开始的思路是最小生成树+树剖。WA了%64。蒟蒻太菜了。

    一直以为是思路的锅。但是最后发现思路并没有问题。最小生成树既然能够保证全局边权和最小,那么就一定能够保证路径上的最长边最短。这个特点是最小生成树的定义能推出的,否则就会自相矛盾。

    后来发现是边转点的锅。因为树剖要把边权转为点权,我们在处理这种问题的时候经常会把边权转为深度较深的节点的点权,这样能保证唯一映射,根节点的点权为0。但是在查询的时候,当查到最后,x,y跳到同一条链上的时候,就不能直接query(1,1,n,id[y],id[x]),因为那样的话就会多加一条边权。

    所以我们变成query(1,1,n,id[y]+1,id[x]),即可保证正确性。

    所以有AC代码:

    #include<cstdio>
    #include<algorithm>
    #define lson pos<<1
    #define rson pos<<1|1
    using namespace std;
    const int maxm=1e5+10;
    const int maxn=1e4+10;
    int n,m,cnt,q,num;
    int f[maxn];
    int tot,to[maxn<<1],nxt[maxn<<1],head[maxn],val[maxn<<1];
    int deep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn],w[maxn],a[maxn];
    int tree[maxn<<2];
    struct node
    {
        int x,y,z;
    }e[maxm];
    bool cmp(node a,node b)
    {
        return a.z<b.z;
    }
    int find(int x)
    {
        if(x==f[x])
            return x;
        return f[x]=find(f[x]);
    }
    void add(int x,int y,int z)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        val[tot]=z;
        head[x]=tot;
    }
    void dfs1(int x,int from)
    {
        deep[x]=deep[from]+1;
        fa[x]=from;
        size[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==from)
                continue;
            a[y]=val[i];
            dfs1(y,x);
            size[x]+=size[y];
            if(!son[x]||size[y]>size[son[x]])
                son[x]=y;
        }
    }
    void dfs2(int x,int t)
    {
        top[x]=t;
        id[x]=++num;
        w[num]=a[x];
        if(!son[x])
            return;
        dfs2(son[x],t);
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==fa[x]||y==son[x])
                continue;
            dfs2(y,y);
        }
    }
    void build(int pos,int l,int r)
    {
        int mid=(l+r)>>1;
        if(l==r)
        {
            tree[pos]=w[l];
            return;
        }
        build(lson,l,mid);
        build(rson,mid+1,r);
        tree[pos]=max(tree[lson],tree[rson]);
    }
    int query(int pos,int l,int r,int x,int y)
    {
        int ret=0;
        int mid=(l+r)>>1;
        if(x<=l && r<=y)
            return tree[pos];
        if(x<=mid)
            ret=max(ret,query(lson,l,mid,x,y));
        if(y>mid)
            ret=max(ret,query(rson,mid+1,r,x,y));
        return ret;
    }
    int q1(int x,int y)
    {
        int ret=0;
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
                swap(x,y);
            ret=max(ret,query(1,1,n,id[top[x]],id[x]));
            x=fa[top[x]];
        }
        if(deep[x]<deep[y])
            swap(x,y);
        ret=max(ret,query(1,1,n,id[y]+1,id[x]));
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n;i++)
            f[i]=i;
        for(int i=1;i<=m;i++)
        {
            int fx=find(e[i].x);
            int fy=find(e[i].y);
            if(fx!=fy)
            {
                f[fx]=fy;
                cnt++;
                add(e[i].x,e[i].y,e[i].z);
                add(e[i].y,e[i].x,e[i].z);
            }
            if(cnt==n-1)
                break;
        }
        dfs1(1,0);
        dfs2(1,1);
        build(1,1,n);
        scanf("%d",&q);
        while(q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            printf("%d
    ",q1(u,v));
        }
        return 0;
    }
    
  • 相关阅读:
    JAVA heap space 内存溢出
    S数据导入
    全部物料的交期都要加上两天 V_OUT_PR
    S初始化生产环境数据
    修改邮件通知模板
    java 工具类使用
    Nginx 搭建图片服务器
    java 枚举类型 Enum
    aop设计原理(转)
    Callable+ThreadPoolExecutor实现多线程并发并获得返回值(转)
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13723867.html
Copyright © 2011-2022 走看看