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;
}

 

posted on 2018-10-24 13:51  Helpp  阅读(170)  评论(0编辑  收藏  举报

导航