zoukankan      html  css  js  c++  java
  • lca 最大生成树 逆向思维 2018 徐州赛区网络预赛j

    题目链接 

    题意:

    有一个n*m的方格

    每个小格子之间有一道墙 给定建这道墙的价格

    要求建一些墙 使得方格内的任意两个小方格之间都只有唯一的一条路径 并且要使这个建墙方式花费最小

    现在给定q组坐标     问这对坐标的路径长度

    思路:树的性质之一是 结点之间只有唯一的一条路径

    通过建立墙来构出一条路径,也可以反过来理解,将墙全部建好,然后再删除一些墙

    这样的话 找出最大生成树 因为这样保证了建的墙的价格最优   

    然后再在最大生成树里面找  两个点的简单路径

    #include<bits/stdc++.h>
    using namespace std;
    
    
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    
    const int N  =1e6+3;
    int n,m;
    
    struct tree{
        int cnt,y[N],z[N],head[N],nxt[N];
        void clc(){
            cnt= 0 ;
            memset(y,0,sizeof(y));
            memset(z,0,sizeof(y));
            memset(head,0,sizeof(y));
            memset(nxt,0,sizeof(y));
        }
        void add(int a,int b,int c){
            y[++cnt] = b;z[cnt]=c;
            nxt[cnt] = head[a];
            head[a] = cnt;
        }
    }e,q;
    
    struct node{
        int u,v,c;
        friend bool operator < (node a,node b){
            return a.c>b.c;
        }
    };
    node edge[N];
    int all;
    
    int pre[N];
    int find(int x){
        return x==pre[x]?x:pre[x]=find(pre[x]);
    }
    bool same(int a,int b){
        return find(a)==find(b);
    }
    void Union(int a,int b){
        pre[find(a)]=find(b);
    }
    
    void krucal(){
        sort(edge,edge+all);
        for(int i=1;i<=n;++i)pre[i]=i;
        for(int i=0;i<all;++i){
            node tmp = edge[i];
            if(!same(tmp.u,tmp.v)){
                e.add(tmp.u,tmp.v,1);
                e.add(tmp.v,tmp.u,1);
                Union(tmp.u,tmp.v);
            }
        }
    }
    int dis[N],vis[N];
    int ans[N];
    int fxa;
    void dfs(int t,int pre){
        for(int i=e.head[t];i;i=e.nxt[i]){
            if(e.y[i]==pre)continue;
            dis[e.y[i]] = dis[t]+e.z[i];
            dfs(e.y[i],t);
        }
    }
    void lca(int t,int fa){
        for(int i=e.head[t];i;i=e.nxt[i]){
            if(e.y[i]==fa)continue;
            lca(e.y[i],t);
            pre[e.y[i]] = t;
        }
        vis[t]=1;
        for(int i=q.head[t];i;i=q.nxt[i]){
            if(vis[q.y[i]] && !ans[q.z[i]]){
                ans[q.z[i]] = dis[t]+dis[q.y[i]]-2*dis[find(q.y[i])];
            }
        }
    }
    
    int main(){
    
        while(cin>>n>>m){
    
            q.clc();e.clc();
            memset(ans,0,sizeof(ans));
            memset(vis,0,sizeof(vis));
            all = 0 ;
    
    
            char d[22],r[22];int v1,v2;
    
            n = n*m;
    
            for(int i=1;i<=n;++i){
                scanf("%s %d %s %d",d,&v1,r,&v2);
                if(d[0]=='D'){
                    edge[all++] = node{i,i+m,v1};
                }
                if(r[0]=='R'){
                    edge[all++] =node{i,i+1,v2};
                }
            }
            int a[4];
            int ask;
            scanf("%d",&ask);
    
            for(int i=1;i<=ask;++i){
                for(int j=0;j<4;++j)scanf("%d",&a[j]);
                int u= a[0]*m-m+a[1];int v = a[2]*m-m+a[3];
                q.add(u,v,i);q.add(v,u,i);
            }
    
            krucal();
    
            dis[1]=0;
            dfs(1,0);
    
            for(int i =1;i<=n;++i)pre[i]=i;
            lca(1,0);
    
            for(int i=1;i<=ask;++i)cout<<ans[i]<<endl;
    
        }
        return 0;
    }
  • 相关阅读:
    读书笔记-编写可读代码的艺术[中]
    读书笔记-编写可读代码的艺术[上]
    读书笔记-编写可读代码的艺术[上]
    单元测试Struts2Spring项目的Action和Service(包含源码)
    单元测试Struts2Spring项目的Action和Service(包含源码)
    单元测试Struts2的Action(包含源码)
    Java实现 LeetCode 223 矩形面积
    Java实现 LeetCode 223 矩形面积
    Java实现 LeetCode 223 矩形面积
    Java实现 LeetCode 222 完全二叉树的节点个数
  • 原文地址:https://www.cnblogs.com/wjhstudy/p/9843184.html
Copyright © 2011-2022 走看看