2018 icpc区域赛徐州赛区网络赛 J题 Maze Designer(最大生成树+lca)

https://nanti.jisuanke.com/t/31462  题目链接

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

建造迷宫,使得任意两点之间只有一条路径,给出两个点,求两个点之间最短路。

第一眼做这个题,以为求最短路呢。。直接写了个spfa,然后WA。。。

这个题可以自己推一下,一个n*m的矩阵,删除(n-1)*(m-1)条边,可以自己推一下,当初我是删除了(n-1)*(m-1)条最短边,然后建图,发现这么删边有一个弊端,就是可能堵死一个方格,不符合题意,然后用的最大生成树来免除这个弊端。那么建立完图了,考虑两个点之间的距离。因为1e6次查询,不可能用跑1e6次最短路,所以可以用lca离线来求距离,因为他们权值默认为1.

1e6次查询,预处理O(n+m),查询O(1)。

这个题我觉得难在建立图上,因为你需要推出一个删除边的数量,和如何去建立这个图,和想到用lca来求距离

附上代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e6 + 100;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int n, m, tot, k, tt;
int f[maxn], h[maxn], arc[maxn], vis[maxn], ans[maxn], path[maxn], dis[maxn], num[maxn];
struct node
{
	int u, v;
	ll w;
	bool operator < (const node &a)const {
		return a.w < w;
	}
}e[maxn];
struct qre
{
	int u, v, index;
	int next;
}query[maxn];
vector<int>vec[maxn];
void init()
{
	for (int i = 0; i <= n * m; i++)
	{
		f[i] = i;
		h[i] = -1;
	}
	memset(arc, 0, sizeof(arc));
	memset(vis, 0, sizeof(vis));
	memset(ans, inf, sizeof(ans));
	memset(dis, 0, sizeof(dis));
	memset(path, -1, sizeof(path));
	k = 0;
	tt = 0;
}
void addedge(int u, int v, int w)
{
	e[k].u = u;
	e[k].v = v;
	e[k++].w = w;
}
void addedge1(int u, int v, int index)
{
	query[tt].u = u;
	query[tt].v = v;
	query[tt].index = index;
	query[tt].next = h[u];
	h[u] = tt++;

	query[tt].u = v;
	query[tt].v = u;
	query[tt].index = index;
	query[tt].next = h[v];
	h[v] = tt++;
	return;
}
int find(int x)
{
	if (x == f[x])
	{
		return x;
	}
	return f[x] = find(f[x]);
}
int find_fa(int x)
{
	if (x == arc[x])
	{
		return x;
	}
	else
	{
		return arc[x] = find_fa(arc[x]);
	}
}
void kru()
{
	tot = n * m;
	for (int i = 0; i < k; i++)
	{
		int u = find(e[i].u);
		int v = find(e[i].v);
		if (u != v)
		{
			if (u < v)
			{
				f[u] = v;
			}
			else
			{
				f[v] = u;
			}
			vec[e[i].u].push_back(e[i].v);
			vec[e[i].v].push_back(e[i].u);
			if (--tot == 1)
			{
				break;
			}
		}
	}
}
void tarjan(int u,int fa)
{
	arc[u] = u;
	vis[u] = true;
	for (int i = 0; i <vec[u].size(); i ++)
	{
		int v = vec[u][i];
		if (vis[v])
		{
			continue;
		}
		dis[v] = dis[u] + 1;
		tarjan(v,u);
	}
	for (int i = h[u]; i != -1; i = query[i].next)
	{
		int v = query[i].v;
		if (vis[v])
		{
			int pp = find_fa(v);
			ans[query[i].index] = abs(dis[u] - dis[pp]) + abs(dis[v] - dis[pp]);
		}
	}
	arc[u] = fa;
}
int main()
{
	//freopen("C://input.txt", "r", stdin);
	scanf("%d%d", &n, &m);
	int l = n * m;
	init();
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			char d, r;
			ll a, b;
			cin >> d >> a >> r >> b;
			int u = (i - 1)*m + j;
			int v;
			if (i < n)
			{
				v = i * m + j;
				addedge(u, v, a);
			}
			if (j < m)
			{
				v = (i - 1)*m + j + 1;
				addedge(u, v, b);
			}
		}
	}
	sort(e, e + k);
	kru();
	int q;
	scanf("%d", &q);
	int llp = 0;
	for (int i = 0; i < q; i++)
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		int u = (x1 - 1) * m + y1;
		int v = (x2 - 1) * m + y2;
		addedge1(u, v, i);
		num[llp++] = v;
	}

	tarjan(1,0);
	for (int i = 0; i < q; i++)
	{
		printf("%d\n", ans[i]);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值