ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer (最大生成树+LCA)

题意:一个N*M的矩形,每个格点到其邻近点的边有其权值,需要构建出一个迷宫,使得构建迷宫的边权之和最小,之后Q次查询,每次给出两点坐标,给出两点之间的最短路径
分析:可以把每个格点视作视作图的点,隔开两点的边视作图的边,则构建迷宫可以视作求其生成树,剩余的边就是组成迷宫的墙.因为要花费最小,所以使删去的墙权置最大即可,呢么就是求最大生成树即可.
然后每次查询相当于查这个最大生成树上任意两点的最短距离,到这一步就是个LCA板子题了.
所以:最大生成树+树上两点最短距离
--来自罗神

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=250005;
struct node{
	int v,dis,next;
}edges[N<<1];
int head[N],e;
int id[N]; //节点第一次被遍历的顺序
int dis[N]; //节点到根节点的距离
int RMQ[N*3][20];
int curID;
//F[i]表示第i个遍历的节点
//B[i]表示F[i]在树中的深度
int F[N*3],B[N*3];
int root;
void init()
{
    e = 0; curID = 0;
    memset(head,-1,sizeof(head));
}
void Add (int u,int v,int dis)
{
	edges[e].v=v;
	edges[e].dis=dis;
	edges[e].next=head[u];
	head[u]=e++;
}

void DFS (int u,int p,int Dep,int d)
{
	int i,v;
	curID++;
	F[curID]=u;
	B[curID]=Dep;
	id[u]=curID;
	dis[u]=d;
	for (i=head[u];i!=-1;i=edges[i].next){
		v=edges[i].v;
		if (v==p) continue;
		DFS(v,u,Dep+1,d+1);
		curID++;
		F[curID]=u;
		B[curID]=Dep;
	}
}

void initRMQ ()
{
	int i,j,x,y;
	for (i=1;i<=curID;i++)
		RMQ[i][0]=i;
	for (j=1;(1<<j)<=curID;j++)
		for (i=1;i+(1<<j)-1<=curID;i++){
			x=RMQ[i][j-1];
			y=RMQ[i+(1<<(j-1))][j-1];
			RMQ[i][j]=B[x]<B[y]?x:y;
		}
}

int getLCA (int a,int b)
{
	int k,x,y;
	a=id[a];b=id[b];
	if (a>b)
		k=a,a=b,b=k;
	k=log(1.0+b-a)/log(2.0);
	x=RMQ[a][k];
	y=RMQ[b-(1<<k)+1][k];
	return B[x]<B[y]?F[x]:F[y];
}

int dist(int x,int y)
{
    return dis[x] +dis[y] - 2*dis[getLCA(x,y)];
}

struct Edg{
    int u,v;
    LL dist;
    bool operator<(const Edg &rhs)const{return dist>rhs.dist;}
};

struct Kruskal{
    int n,m;
    Edg edges[N<<1];
    int fa[N];
    int findset(int x){ return fa[x]==-1?x:fa[x]=findset(fa[x]); }

    void init(int n){
        this->n=n;
        m=0;
        memset(fa,-1,sizeof(fa));
    }

    void AddEdge(int u,int v,LL dist){
        edges[m++] = (Edg){u,v,dist};
    }

    void kruskal(){
        LL sum=0;
        int cnt=0;
        sort(edges,edges+m);
        for(int i=0;i<m;i++){
            int u=edges[i].u, v=edges[i].v;
            if(findset(u) != findset(v)){
                Add(u,v,1);
                Add(v,u,1);
                sum +=edges[i].dist;
                fa[findset(u)] = findset(v);
                if(++cnt>=n-1) return ;
            }
        }
        return ;
    }
}G;

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int n,m;
    char c1,c2;
    LL w1,w2;
    while(scanf("%d %d",&n,&m)==2){
        init();
        G.init(n*m+1);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                scanf("
%c %lld %c %lld",&c1,&w1,&c2,&w2);
                if(c1=='D'){
                    G.AddEdge((i-1)*m+j,i*m+j,w1);
                }
                if(c2 == 'R'){
                    G.AddEdge((i-1)*m+j,(i-1)*m+j+1,w2);
                }
            }
        }
        G.kruskal();
        root=1;
        DFS(root,0,0,0);
        initRMQ();
        int Q; scanf("%d",&Q);
        int x1,y1,x2,y2;
        while(Q--){
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            int u = (x1-1)*m+y1, v = (x2-1)*m+y2;
            printf("%d
",dist(u,v));
        }
    }
    return 0;
}

为了更好的明天
原文地址:https://www.cnblogs.com/xiuwenli/p/9614184.html