徐州网络赛J-Maze Designer【最小生成树】【LCA】

After the long vacation, the maze designer master has to do his job. A tour company gives him a map which is a rectangle. The map consists of N \times MN×M little squares. That is to say, the height of the rectangle is NN and the width of the rectangle is MM. The master knows exactly how the maze is going to use. The tour company will put a couple in two different squares in the maze and make them seek each other. Of course,the master will not make them find each other easily. The only thing the master does is building some wall between some little squares. He knows in that way, wherever the couple is put, there is only one path between them. It is not a difficult thing for him, but he is a considerate man. He also knows that the cost of building every wall between two adjacent squares is different(Nobody knows the reason). As a result, he designs the maze to make the tour company spend the least money to build it.

Now, here's your part. The tour company knows you're the apprentice of the master, so they give you a task. you're given QQ qustions which contain the information of where the couple will be put. You need to figure out the length of the shortest path between them.

However,the master doesn't tell you how he designs the maze, but he believes that you, the best student of himself, know the way. So he goes on vacation again.

Input

The first line of the input contains two integers NN and MM (1 \le N,M \le 5001≤N,M≤500), giving the number of rows and columns of the maze.

The next N \times MN×M lines of the input give the information of every little square in the maze, and their coordinates are in order of (1,1)(1,1) , (1,2)(1,2) \cdots⋯ (1,M)(1,M) , (2,1)(2,1) , (2,2)(2,2) , \cdots⋯ , (2,M)(2,M) , \cdots⋯ ,(N,M)(N,M).

Each line contains two characters DD and RR and two integers aa , bb (0 \le a,b \le 20000000000≤a,b≤2000000000 ), aa is the cost of building the wall between it and its lower adjacent square, and bb is the cost of building the wall between it and its right adjacent square. If the side is boundary, the lacking path will be replaced with X 00.

The next line contains an integer QQ (1 \le Q \le 1000001≤Q≤100000 ), which represents the number of questions.

The next QQ lines gives four integers, x_1x1​, y_1y1​, x_2x2​, y_2y2​ ( 1 \le x_11≤x1​ , x_2 \le Nx2​≤N , 1 \le y_11≤y1​ , y_2 \le My2​≤M ), which represent two squares and their coordinate are (x_1x1​ , y_1y1​) and (x_2x2​ , y_2y2​).

(xx,yy) means row xx and column yy.

It is guaranteed that there is only one kind of maze.

Output

For each question, output one line with one integer which represents the length of the shortest path between two given squares.

样例输入复制

3 3
D 1 R 9
D 7 R 8
D 4 X 0
D 2 R 6
D 12 R 5
D 3 X 0
X 0 R 10
X 0 R 11
X 0 X 0
3
1 1 3 3
1 2 3 2
2 2 3 1

样例输出复制

4
2
2

题目来源

ACM-ICPC 2018 徐州赛区网络预赛

 

题意:

有一个n*m的方格

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

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

现在给定q组坐标

问这对坐标的路径长度

思路:

应该要想到树的性质之一是 结点之间只有唯一的一条路径

这道题相当于把小格子转换为节点 墙转换为边 花费转换为权值

构造一棵最大生成树 不在树中的这些边表示需要建墙

对于每一组查询 查找最近公共祖先 深度之差的和即为答案

 

一直只过了8组样例 WA到现在还不知道什么问题

有时间可能需要重新写一下 显示说是段错误 但是我数组什么的好像也已经开的足够大了啊

可能哪里访问有点问题


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#define inf 0x7f7f7f7f7f7f7f7f
using namespace std;
typedef long long LL;

const int maxn = 600;
LL n, m, cntedge;
LL depth[maxn * maxn], upfa[maxn * maxn][30], par[maxn * maxn];

struct edge {
	LL u, v;
	LL cost;
}e[maxn * maxn * 2];
vector etree[maxn * maxn];

bool cmp(edge a, edge b)
{
	return a.cost > b.cost;
}

void dfs(LL u, LL pre, LL d)
{
	upfa[u][0] = pre;
	depth[u] = d;
	for (LL i = 0; i < etree[u].size(); i++) {
		LL v = etree[u][i].v;
		if (v != pre) {
			dfs(v, u, d + 1);
		}
	}
}

void initlca()
{
	dfs(0, -1, 0);
	for (LL j = 0; (1 << (j + 1)) < n * m; j++) {
		for (LL i = 0; i < n * m; i++) {
			if (upfa[i][j] < 0) {
				upfa[i][j + 1] = -1;
			}
			else {
				upfa[i][j + 1] = upfa[upfa[i][j]][j];
			}
		}
	}
}

void init()
{
	for (LL i = 0; i < n * m; i++) {
		par[i] = i;
		etree[i].clear();
	}

	memset(depth, 0, sizeof(depth));
	memset(upfa, -1, sizeof(upfa));
	cntedge = 0;
}

LL lca(LL u, LL v)
{
	if (depth[u] > depth[v]) {
		swap(u, v);
	}
	LL temp = depth[v] - depth[u];
	for (LL i = 0; (1 << i) <= temp; i++) {
		if ((1 << i) & temp) {
			v = upfa[v][i];
		}
	}
	if (v == u) return u;
	for (LL i = (LL)log2(n * m * 1.0); i >= 0; i--) {
		if (upfa[u][i] != upfa[v][i]) {
			u = upfa[u][i];
			v = upfa[v][i];
		}
	}
	return upfa[u][0];
}

int find(int x)
{
	LL rt = x;
	while (rt != par[rt]) {
		rt = par[rt];
	}
	while (x != rt) {
		LL t = par[x];
		par[x] = rt;
		x = t;
	}
	return rt;
}

void unite(LL x, LL y)
{
	x = find(x);
	y = find(y);
	if (x != y) {
		par[x] = y;
	}
}


void kruskal()
{
	sort(e, e + cntedge, cmp);
	LL nedge = 0;
	for (LL i = 0; i < cntedge && nedge < m * n - 1; i++) {
		if (find(e[i].u) != find(e[i].v)) {
			etree[e[i].u].push_back(e[i]);
			edge tmp;
			tmp.u = e[i].v;
			tmp.v = e[i].u;
			tmp.cost = e[i].cost;
			etree[tmp.u].push_back(tmp);
			unite(e[i].u, e[i].v);
			nedge++;
		}
	}
}


int main()
{
	scanf("%lld%lld", &n, &m);
	init();
	for (LL i = 0; i < n * m; i++) {
		char ch1[5], ch2[5];
		LL a, b;
		scanf("%s %lld %s %lld", ch1, &a, ch2, &b);
		if (ch1[0] != 'X') {
			e[cntedge].u = i;
			e[cntedge].v = i + m;
			e[cntedge].cost = a;
			cntedge++;
			e[cntedge].u = i + m;
			e[cntedge].v = i;
			e[cntedge].cost = a;
			cntedge++;
		}
		if (ch2[0] != 'X') {
			e[cntedge].u = i;
			e[cntedge].v = i + 1;
			e[cntedge].cost = b;
			cntedge++;
			e[cntedge].u = i + 1;
			e[cntedge].v = i;
			e[cntedge].cost = b;
			cntedge++;
		}
	}

	LL q;
	kruskal();
	initlca();
	scanf("%lld", &q);
	while (q--) {
		LL x1, x2, y1, y2;
		scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
		x1--; y1--; x2--; y2--;
		LL father = lca(x1 * m + y1, x2 * m + y2);
		LL ans = depth[x1 * m + y1] - 2 * depth[father] + depth[x2 * m + y2];
		printf("%lld\n", ans);
	}


	return 0;
}

找到的AC 代码:

#include 
const int maxn = 507;
struct { int next, v; } edge[maxn * maxn << 1];
int dep[maxn * maxn], n, m, up[maxn * maxn][27], tot, q;
int index(int x, int y) { return (x - 1) * m + y; }
namespace graph {
    int head[maxn * maxn], cnt;
    void addedge(int u, int v) {
        edge[++cnt] = {head[u], v};
        head[u] = cnt;
    }
}
void bfs() {
    memset(up, 0xff, sizeof(up));
    std::queue que;
    que.push(1);
    dep[1] = 1;
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        for (int i = graph::head[u]; i; i = edge[i].next) {
            int v = edge[i].v;
            if (dep[v] == 0) {
                dep[v] = dep[u] + 1;
                up[v][0] = u;
                que.push(v);
            }
        }
    }
    for (int j = 1; j <= 22; j++) {
        for (int i = 1; i <= n * m; i++) {
            if (~up[i][j - 1]) up[i][j] = up[up[i][j - 1]][j - 1];
        }
    }
}
int query(int u, int v) {
    if (dep[u] < dep[v]) std::swap(u, v);
    int tmp = dep[u] - dep[v];
    for (int j = 0; tmp; j++) if (tmp & (1 << j)) tmp ^= (1 << j), u = up[u][j];
    if (u == v) return u;
    for (int j = 22; ~j; j--) if (up[u][j] != up[v][j]) u = up[u][j], v = up[v][j];
    return up[u][0];
}
struct Disjoint {
    int pre[maxn * maxn];
    Disjoint() { for (int i = 0; i < maxn * maxn; i++) pre[i] = i; }
    int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); }
    void merge(int x, int y) { if (x != y) pre[x] = y; }
} disjoint;
struct Edge { int u, v, cost; } edges[maxn * maxn << 1];
int main() {
    scanf("%d%d", &n, &m);
    char ch;
    for (int i = 1, cost; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            for (int k = 0; k < 2; k++) {
                scanf(" %c%d", &ch, &cost);
                if (ch != 'X') {
                    if (ch == 'R') edges[tot++] = {index(i, j), index(i, j + 1), cost};
                    else edges[tot++] = {index(i, j), index(i + 1, j), cost};
                }
            }
        }
    }
    std::sort(edges, edges + tot, [](Edge x, Edge y) { return x.cost > y.cost; });
    for (int i = 0; i < tot; i++) {
        int u = disjoint.find(edges[i].u), v = disjoint.find(edges[i].v);
        if (u != v) {
            graph::addedge(edges[i].u, edges[i].v);
            graph::addedge(edges[i].v, edges[i].u);
            disjoint.merge(u, v);
        }
    }
    bfs();
    scanf("%d", &q);
    for (int i = 0, x, y, a, b; i < q; i++) {
        scanf("%d%d%d%d", &x, &y, &a, &b);
        int u = index(x, y), v = index(a, b), lca = query(u, v);
        printf("%d\n", dep[u] + dep[v] - 2 * dep[lca]);
    }
    return 0;
}

 

你可能感兴趣的:(还不会,LCA,最小生成树)