zoukankan      html  css  js  c++  java
  • [NOIP2013]货车运输,最大生成树+LCA

    codevs3287
    之前写过一个pascal版本的,年代有点久远了

    既然问最大的运货重量,那么每次都选众多路径中最大的边都显然是对的
    那么把原本的图变成一颗最大生成树,选权值最大的n-treenum条边(treenum是联通块数量)
    好吧,其实是个森林,
    那么现在就变成了求树上简单路径上的最值
    树上简单路径,,LCA咯,
    同时可以像维护st表一样维护一个树上的RMQ
    当然这里不能像st表一样暴力重叠,不能重叠,看看lca的套路,咱们二进制拆分吧
    fa[x][i]:x节点向上2的i次方的祖先
    di[x][i]:从x节点走到fa[x][i]的最大权值

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int INF=0x3f3f3f3f;
    const int N = 1e5 + 5;
    int n,m;
    
    struct gragh{
        struct Edge{
            int from,to,w;
            Edge(){}
            Edge(int x,int y,int z):from(x),to(y),w(z){}
            bool operator < (const Edge& a)const{
                return w < a.w;
            }
        }edges[N],be[N];
        int E,f[N],fa[N][20],di[N][20],dep[N];
        bool vis[N];
        vector<int >G[N];
        int F(int x){//并查集
            return f[x]==x?x:(f[x]=F(f[x]));
        }
    
        inline void link(int x,int y,int z){
            edges[++E]=Edge(x,y,z);
            G[x].push_back(E);
        }
    
        void build(){
            E=0;
            for (int i=1;i<=n;i++)G[i].clear();
            int x,y,z;
            for (int i=1;i<=n;i++)f[i]=i;
            for (int i=1;i<=m;i++){
                scanf("%d%d%d",&x,&y,&z);
                be[i]=Edge(x,y,z);
                f[F(x)]=F(y);
            }
        }
    
        void kruskal(){
            int treenum = 0;//forests
            memset(vis,0,sizeof(vis));
            for (int i=1;i<=n;i++)if (!vis[F(i)]){
                treenum++;vis[F(i)]=1;
            }
            for (int i=1;i<=n;i++)f[i]=i;
            sort(be+1,be+m+1);
            int cnt = 0;
            for (int i=m;i>=1;i--){
                int x = be[i].from;
                int y = be[i].to  ;
                if (F(x)==F(y))continue;
                f[F(x)]=F(y);
                cnt++;
                link(x,y,be[i].w);
                link(y,x,be[i].w);
                if (cnt==n-treenum)break;
            }
        }
    
        void dfs(int x){
            vis[x] = 1;
            for (int i=1;i<=17;i++){
                if(dep[x]<(1<<i))break;
                fa[x][i]=fa[fa[x][i-1]][i-1];
                di[x][i]=min(di[x][i-1],di[fa[x][i-1]][i-1]);
            }
            for (int i=0;i<G[x].size();i++){
                Edge e = edges[G[x][i]];
                if (vis[e.to])continue;
                fa[e.to][0] = x;
                di[e.to][0] = e.w;
                dep[e.to] = dep[x]+1;
                dfs(e.to);
            }
        }
    
        int lca(int x,int y){
            if (dep[x]<dep[y])swap(x,y);
            int t = dep[x] - dep[y];
            for (int i=0;i<=17;i++)
                if ((1<<i)&t) x = fa[x][i];
            for (int i=17;i>=0;i--)
                if (fa[x][i]!=fa[y][i]){
                x=fa[x][i];y=fa[y][i];
            }
            if (x==y)return x;
            return fa[x][0];
        }
    
        int ask(int x,int f){//f:father
            int ans = INF;
            int t = dep[x]-dep[f];
            for (int i=0;i<=17;i++)if(t&(1<<i)){
                ans=min(ans,di[x][i]);
                x = fa[x][i];
            }
            return ans;
        }
    
        void work(){
            build();
            kruskal();
            memset(vis,0,sizeof(vis));
            for (int i=1;i<=n;i++)if(!vis[i])dfs(i);
            int q,x,y;
            scanf("%d",&q);
            while (q--){
                scanf("%d%d",&x,&y);
                if (F(x)!=F(y))puts("-1");
                else {
                    int t = lca(x,y);
                    x = ask(x,t);
                    y = ask(y,t);
                    printf("%d
    ",min(x,y));
                }
            }
        }
    }g;
    
    int main(){
        //freopen("truck.in","r",stdin);
        //freopen("truck.out","w",stdout);
        for (;~scanf("%d%d",&n,&m);)g.work();
        return 0;
    }
    

    长代码写的要仔细一点

  • 相关阅读:
    猫眼 top_100 爬取 ___只完成了第一页
    内涵段子——脑筋急转弯——spider
    django 常用 详解
    获取定位信息
    对AFNetworking的二次封装
    对UIImageView+WebCache的封装
    CoreText 实现图文混排
    剖析RAC中的@weakify、@strongify
    实现点击按钮旋转动画
    java面向对象编程思想的理解
  • 原文地址:https://www.cnblogs.com/cww97/p/12349383.html
Copyright © 2011-2022 走看看