Zoj 3195 Design the city

Obviously, it's kind of LCA problem.

I assume that you guys have already learned about LCA stuff :).

So I just talk about the main idea of my method.

Our goal is to connect three specific node by using shortest path.

So we choose a node as root (ie. 0), transform the tree to an array (LCA->RMQ), calculate the depth of each node and get the distance between root and all nodes.

define:

ta: tree array

dep[i]:  depth of node i

dis[i]: the distance between root and node i


Then, for each query, we calculate the LCA to each pair of nodes.

Sort  all the nodes(include that three nodes and their LCA) in ascending order according to  their depth.

Delete all duplicate elements in the array(use unique function)

Then scan the array sequentially.

 For each element a[i] we scan the array again but in reverse direction until we find an ta[j] (j < i) that LCA(ta[i], ta[j]) = ta[j], then calculate the distance dis[ta[i]] - dis[ta[j]] and add it to the result, break sub-scan.

why? because we sort them in ascending order,  the most lowest ancient of a[i] must be the righest ta[j] (LCA(ta[i], ta[j]) = ta[j]).

Besides, it's a tree which mean that there only exists one path between any two node, we can add dis[ta[i]] - dis[ta[j]] to the result without any duplicates.

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <cctype>
#include <queue>
#include <stack>
using namespace std;
#define MS(c, a) memset(c, a, sizeof c)
#define Rep(c, a, b) for (int c = (a); c < (b); c++)
#define Nre(c, a, b) for (int c = (a); c > (b); c--)
#define MAXN (50050 << 1)

struct Edge
{
	int v, w, next;
};
vector<Edge> E;
int L[MAXN];
void G_ini() //Graph initialize
{
	E.clear();
	MS(L, -1);
}
void AE(int u, int v, int w) //Add Edge
{
	Edge te = {v, w, L[u]};
	L[u] = E.size();
	E.push_back(te);
}

int n, q, dep[MAXN], ind, ta[MAXN], id[MAXN], dis[MAXN];

void TTI(int u, int fa) //Tree to Interval
{
	if (fa != -1) dep[u] = dep[fa] + 1;
	id[u] = ind;
	ta[ind++] = u;
	for (int i = L[u]; i != -1; i = E[i].next)
		if (E[i].v != fa)
		{
			dis[E[i].v] = dis[u] + E[i].w;
			TTI(E[i].v, u);
			ta[ind++] = u;
		}
}

int st[20][MAXN];
int low(int x) //lowest power
{
	int o = 0;
	while ((1 << o) <= x) o++;
	return o;
}
void st_ini() //sparse table initialize
{
	Rep(i, 0, ind) st[0][i] = ta[i];
	int l = low(ind);
	Rep(i, 1, l) Rep(j, 0, ind)
		if (j + (1 << i) < ind)
		{
			int x = st[i - 1][j],
				y = st[i - 1][j + (1 << (i - 1))];
			st[i][j] = (dep[x] < dep[y])? x: y;
		}
}
int rmq(int x, int y) //Range minimum query
{
	x = id[x];
	y = id[y];
	if (x > y) swap(x, y);
	int l = low(y - x + 1) - 1;
	x = st[l][x];
	y = st[l][y - (1 << l) + 1];
	return (dep[x] < dep[y])? x: y;
}

bool cmp(int p, int q)
{
	if (dep[p] != dep[q]) return dep[p] < dep[q];
	return p < q;
}

int main()
{
	bool spa = 0;
	while (~scanf("%d", &n))
	{
		if (spa) puts(""); 
		spa = 1;
		G_ini();
		Rep(i, 0, n - 1)
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			AE(u, v, w);
			AE(v, u, w);
		}
		MS(dep, 0);
		MS(dis, 0);
		TTI(ind = 0, -1); //LCA->RMQ
		st_ini();
		scanf("%d", &q);
		vector<int> x;
		while (q--)
		{
			int tx;
			x.clear();
			Rep(i, 0, 3)
			{
				scanf("%d", &tx);
				x.push_back(tx);
			}
			tx = x.size();
			Rep(i, 0, tx) Rep(j, 0, tx) //Calculate LCA of all pair of nodes and add it to the candidate array
				x.push_back(rmq(x[i], x[j]));
			sort(x.begin(), x.end(), cmp); //Sort them in ascending order according to their depth
			x.erase(unique(x.begin(), x.end()), x.end()); //Delete duplicate element
			int res = 0; //Result
			Rep(i, 1, x.size())
				Nre(j, i - 1, -1)
				{
					if (rmq(x[i], x[j]) == x[j]) //find the lowest ancient, add the distance to result and break
					{
						res += dis[x[i]] - dis[x[j]];
						break;
					}
				}
			printf("%d\n", res);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值