zoukankan      html  css  js  c++  java
  • [p1967] 货车运输

    题目


    这道题是贪心加倍增

    首先要贪心的找出一棵最大生成树(题目中要求的是每个点到替他点的最优路径上,每条边的最小值,而不是最短路。建立一棵树,这样就能使所有点都联通。)

    在树上做lca。

    因为两点之间的边最大权值=两个点分别到最近公共祖先的边的权值的最大值

    这样的话。就可以使用倍增

    使用两个倍增数组

    一个数组为为第i个点跳2^j步后到达的节点

    另一个为第i个点跳2^j步后到达的节点与第i个点之间的最小权值

    在线查询

    #include<iostream> 
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    struct ll
    {
        int point1;
        int point2;
        int weight;
    };
    ll l[50100];//克鲁斯卡尔的数组
    struct node
    {
        int point;
        int next;
        int value;
    };
    node line[101000];//邻接表
    int head[10100],tail;
    void add(int x,int y,int val)//添加边
    {
        line[++tail].point=y;
        line[tail].value=val;
        line[tail].next=head[x];
        head[x]=tail;
    }
    bool compare(const ll &a,const ll &b)
    {
        return a.weight>b.weight;
    }
    int color[10100];//染色,判断是不是一个树中。然而luogu数据太弱辣!!没有这个也行
    int t[10100][20];//tree的倍增
    int minn[10100][20];//
    int dep[10100];
    void dfs(int now,int fa,int col,int dis)//预处理
    {
        dep[now]=dep[fa]+1;
        t[now][0]=fa;
        minn[now][0]=dis;
        color[now]=col;
        for(int i=1;(1<<i)<dep[now];i++)
        {
            t[now][i]=t[t[now][i-1]][i-1];
            minn[now][i]=min(minn[now][i-1],minn[t[now][i-1]][i-1]);
        }
        int need=head[now];
        while(need!=-1)
        {
            if(line[need].point!=fa)
                dfs(line[need].point,now,col,line[need].value);
            need=line[need].next;
        }
        return ;
    }
    void lca(int x,int y)//lca
    {
        int ans=0x7fffffff;
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=16;i>=0;i--)
            if(dep[t[x][i]]>=dep[y])
            {
                ans=min(ans,minn[x][i]);
                x=t[x][i];
            }
        if(x!=y)//判断是不是一个点
        {
            
            for(int i=16;i>=0;i--)
            {
                if(t[x][i]!=t[y][i])
                {
                    ans=min(ans,min(minn[x][i],minn[y][i]));
                    x=t[x][i];
                    y=t[y][i];
                }
            }
            ans=min(ans,min(minn[x][0],minn[y][0]));
        }
        printf("%d
    ",ans);
        return ;
    }
    int f[10100];
    int find(int x)
    {
        if(f[x]==x)
            return x;
        return f[x]=find(f[x]);
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            head[i]=-1;
            f[i]=i;
        }
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&l[i].point1,&l[i].point2,&l[i].weight);
        sort(l+1,l+1+m,compare);
        int i=1;
        while(i<=m)
        {
            int f1=find(l[i].point1),f2=find(l[i].point2);
            if(f1!=f2)
            {
                f[f1]=f2;
                add(l[i].point1,l[i].point2,l[i].weight);
                add(l[i].point2,l[i].point1,l[i].weight);
            }
            i++;
        }
        int c=0;
        for(i=1;i<=n;i++)
        {
            if(!color[i])
                dfs(i,0,++c,0);
        }
        int num;
        scanf("%d",&num);
        int a,b;
        for(int i=1;i<=num;i++)
        {
            scanf("%d%d",&a,&b);
            if(color[a]!=color[b])//如果不在一个树中
                printf("-1
    ");
            else
                lca(a,b);
        }
    }
    /*
    输入
    5 2
    1 2 3
    3 4 5
    1
    3 4
    输出
    5
    */
    
  • 相关阅读:
    磁盘及分区管理
    用户和文件权限管理
    分割文件命令split
    去除重复命令uniq
    数据连接命令join
    数据剪切命令cut和数据粘贴命令pastte
    排序命令sort
    koa-router
    koa入门
    require.ensure的用法;异步加载-代码分割;
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/8521194.html
Copyright © 2011-2022 走看看