TopCoder SRM716 Div1 Middle

Posted on By 二价氢

题意

给定一棵树,能否找到一条路径$x_0, x_1, x_2\ldots, x_n$,使得$x_0 = 0$,$Set{D(x_i, x_{i+1})} = S$

思路

如果存在长度为$A$的路径,那么一定存在长度为$A-1$的路径。

考虑建一个新的图,使得图中的每条边的长度都在S中,则答案就是询问是否存在一个点$p$,使得能从0沿新的图走到$p$,且满足距离$p$最远的点的距离大于等于$S$中最大的元素。

Code

耗时: 3911 ms

内存: 28192 kB

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2000 + 5;

struct JumpDistancesOnTree{
	vector<int> e[maxn], e2[maxn];
	unordered_set<int> S;
	int dd[maxn], fur[maxn];
	int flag[maxn];
	void getdist(int u)
	{
		memset(dd, 0x3f, sizeof dd);
		dd[u] = 0;
		queue<int> q;
		q.push(u);
		while (!q.empty())
		{
			int u = q.front();q.pop();
			for (int i = 0; i < (int)e[u].size(); i++)
			{
				if (dd[e[u][i]] > dd[u] + 1)
				{
					dd[e[u][i]] = dd[u] + 1;
					q.push(e[u][i]);
				}
			}
		}
	}
	string isPossible(vector<int> p, vector<int> s)
	{
		int mx = 0;
		memset(fur, 0, sizeof fur);
		for (int i = 0; i < (int)s.size(); i++)
			S.insert(s[i]);
		mx = s[s.size() - 1];
		int n = p.size() + 1;
		for (int i = 0; i < (int)p.size(); i++)
		{
			e[p[i]].push_back(i + 1);
			e[i + 1].push_back(p[i]);
		}
		for (int i = 0; i < n; i++)
		{
			getdist(i);
			for (int j = 0; j < n; j++)
			{
				if (S.find(dd[j]) != S.end())
				{
					fur[i] = max(fur[i], dd[j]);
					e2[i].push_back(j);
				}
			}
		}
		queue<int> q;
		q.push(0);
		memset(flag, 0, sizeof flag);
		flag[0] = 1;
		while (!q.empty())
		{
			int u = q.front(); q.pop();
			for (int i = 0; i < (int)e2[u].size(); i++)
			{
				if (!flag[e2[u][i]])
				{
					flag[e2[u][i]] = 1;
					q.push(e2[u][i]);
				}
			}
		}
		for (int i = 0; i < n; i++)
			if (flag[i] && fur[i] >= mx) return "Possible";
		return "Impossible";
	}
};