zoukankan      html  css  js  c++  java
  • 【洛谷1967】货车运输(最大生成树+倍增LCA)

    点此看题面

    大致题意:(n)个城市和(m)条道路,每条道路有一个限重。多组询问,每次询问从(x)(y)的最大载重为多少。

    一个贪心的想法

    首先,让我们来贪心一波。

    由于要求最大载重,显然要让最小限重尽量大

    不难发现,想要让最小限重尽量大,所经过的路径一定都在原图的最大生成树上。

    于是,我们就可以用求最大生成树的方法来将原图转化为一棵树。

    这样一来,原题就转化成了求树上两点之间的最小边权值

    这应该是可以直接用倍增(LCA) 来搞的吧。

    如何用倍增(LCA)求树上两点之间的最小边权值

    不难想到,我们可以用(Min_{i,j})来表示(i)(fa_{i,j}) 所经过的路径上的最小边权值。

    因此,我们只需在(LCA)的过程中每一次更新节点为当前节点祖先时,加上更新最小值的步骤即可,代码还是很简洁的。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define uint unsigned int
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define abs(x) ((x)<0?-(x):(x))
    #define Fsize 100000
    #define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
    #define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
    #define N 10000
    #define M 50000
    #define add(x,y,z) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=z)
    int FoutSize=0,OutputTop=0;char Fin[Fsize],*FinNow=Fin,*FinEnd=Fin,Fout[Fsize],OutputStack[Fsize];
    using namespace std;
    int n,m,ee=0,fa[N+5],lnk[N+5]={0},Depth[N+5],vis[N+5]={0},f[N+5][20],Min[N+5][20];
    struct line//题目中给定图的边
    {
        int x,y,v;
    }w[M+5];
    struct edge//原图最大生成树的边
    {
        int to,nxt,val;
    }e[2*N+5];
    inline void read(int &x)
    {
        x=0;static char ch;
        while(!isdigit(ch=tc()));
        while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    }
    inline void write(int x)
    {
        if(!x) return (void)pc('0');
        while(x) OutputStack[++OutputTop]=x%10+48,x/=10;
        while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;
    }
    inline bool cmp(line x,line y)//将原图给定的边排序
    {
        return x.v>y.v;
    }
    inline int getfa(int x)//并查集函数
    {
        return fa[x]^x?fa[x]=getfa(fa[x]):x;
    }
    inline void dfs(int x)//dfs初始化
    {
        register int i;
        for(i=1;i<20;++i) f[x][i]=f[f[x][i-1]][i-1],Min[x][i]=min(Min[x][i-1],Min[f[x][i-1]][i-1]);//计算出f数组和Min数组
        for(vis[x]=1,i=lnk[x];i;i=e[i].nxt)//枚举当前节点的相邻节点
        {
            if(!(e[i].to^f[x][0])) continue;//如果枚举到的节点是当前节点的父亲节点,就跳过
            Depth[e[i].to]=Depth[f[e[i].to][0]=x]+1,Min[e[i].to][0]=e[i].val,dfs(e[i].to);//初始化子节点信息,并dfs该子节点
        }
    }
    inline int Query(int x,int y)//询问操作,类似于求LCA的过程
    {
        register int i,res=1e9;//res记录答案
        if(Depth[x]<Depth[y]) swap(x,y);
        for(i=0;Depth[x]^Depth[y];++i) if((Depth[x]-Depth[y])&(1<<i)) res=min(res,Min[x][i]),x=f[x][i];//在更新当前节点为当前节点祖先的同时,也要更新最小值
        if(!(x^y)) return res;//如果x与y已经相等,就返回res
        for(i=0;f[x][i]^f[y][i];++i);
        for(--i;i>=0;--i) if(f[x][i]^f[y][i]) res=min(res,min(Min[x][i],Min[y][i])),x=f[x][i],y=f[y][i];//在更新当前节点为当前节点祖先的同时,也要更新最小值
        return min(res,min(Min[x][0],Min[y][0]));//返回x,y到父亲的边权与res中的较小值
    }
    int main()
    {
        register int i,Q,x,y,fx,fy;
        for(read(n),read(m),i=1;i<=m;++i) read(w[i].x),read(w[i].y),read(w[i].v);//读入原图
        for(sort(w+1,w+m+1,cmp),i=1;i<=n;++i) fa[i]=i;//初始化并查集
        for(i=1;i<=m;++i) if((fx=getfa(w[i].x))^(fy=getfa(w[i].y))) fa[fx]=fy,add(w[i].x,w[i].y,w[i].v),add(w[i].y,w[i].x,w[i].v);//Kruskal最大生成树
        for(read(Q);Q;--Q)//对于每个询问进行操作
        {
            read(x),read(y);
            if(getfa(x)^getfa(y)) {pc('-'),pc('1'),pc('
    ');continue;}//如果不在同一个联通块内,直接输出-1
            if(!vis[x]||!vis[y]) dfs(x);//如果这个联通块未访问过,就dfs遍历一遍初始化
            write(Query(x,y)),pc('
    ');//输出两点之间的最小边权
        }
        return fwrite(Fout,1,FoutSize,stdout),0;
    }
    
  • 相关阅读:
    代码、复制[置顶] 跑起来,第一个sshby小雨
    返回、参数了解Javascript函数:parseInt()by小雨
    代码、复制Javascript执行效率小结by小雨
    图片、JQuery学习笔记(图片的展开和伸缩)by小雨
    登录、项目Spring mvc Session拦截器by小雨
    社区、标签jsp中获取状态怎么写?by小雨
    升级、地方LKDBHelper 使用FMDB 对数据库的自动操作by小雨
    广播、应用Android BroadcastReceiver(一)by小雨
    调试、手机手游开发知识(三)--NDK联机调试by小雨
    设置、数值【Cocos2DX 】初窥门径(11)CCUserDefault:保存数据by小雨
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1967.html
Copyright © 2011-2022 走看看