bzoj4151 [AMPPZ2014]The Cave

Description

给定一棵有 \(n\) 个节点的树,相邻两点之间的距离为 \(1\)

请找到一个点 \(x\) ,使其满足所有 \(m\) 条限制,其中第i条限制为 \(dist(x,a[i])+dist(x,b[i])\le d[i]\)

Input

第一行包含一个正整数 \(t(1 \le t \le 1000)\) ,表示数据组数。

对于每组数据,第一行包含两个正整数 \(n,m(2\le n,m\le 300000)\) ,表示点数、限制数。

接下来 \(n-1\) 行,每行两个正整数 \(x,y(1\le x,y\le n)\) ,表示树上的一条边。

接下来 \(m\) 行,每行三个正整数 $a[i],b[i],d[i] (1\le a[i],b[i]\le n,1\le d[i]\le 600000) $ ,描述一条限制。

输入数据保证所有 \(n\) 之和不超过 \(300000\) ,所有 \(m\) 之和也不超过 \(300000\)

Output

输出 \(t\) 行。第 \(i\) 行输出第 \(i\) 组数据的答案,如果无解输出 \(\mathrm{NIE}\) ,否则输出 \(\mathrm{TAK}\)

然后输出 \(x\) ,如有多组解,输出任意一组。

Sample

Sample Input

2
5 3
1 2
2 3
2 4
3 5
1 4 2
5 5 5
3 2 1
3 2
1 2
2 3
1 1 2
3 3 1

Sample Output

TAK 2
NIE

Solution

\(\mathrm{Azrael \_ Death}\) 巨巨的强力推荐下做了此题。

好题,完全没想到正解。

可参考另一篇写得很清楚的博客:BZOJ4151【AMPPZ2014】The Cave <树相关>

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

#define N 300001
#define rep(i, a, b) for (int i = a; i <= b; i++)

inline int read() {
	int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}

int n, m, head[N], tot, dis[4][N], a[N], b[N], d[N];
struct edge { int v, next; }e[N << 1];
inline void add(int u, int v) { e[++tot].v = v, e[tot].next = head[u], head[u] = tot; }

void dfs(int u, int fa, int dep, int t) {
	dis[t][u] = dep;
	for (int i = head[u]; i; i = e[i].next) if (e[i].v != fa) dfs(e[i].v, u, dep + 1, t);
}

int main() {
	for (int T = read(); T--;) {
		n = read(), m = read(); memset(head, 0, sizeof head), tot = 0;
		rep(i, 2, n) { int u = read(), v = read(); add(u, v), add(v, u); }
		dfs(1, 0, 0, 0);
		int mx = -1, mn = 0x7fffffff, p;
		rep(i, 1, m) {
			a[i] = read(), b[i] = read(), d[i] = read();
			int t = max(0, dis[0][a[i]] + dis[0][b[i]] - d[i]);
			if (t > mx) mx = t, p = i;
		}
		dfs(a[p], 0, 0, 1), dfs(b[p], 0, 0, 2);
		int tmp = d[p]; p = 0;
		rep(i, 1, n) if (dis[1][i] + dis[2][i] <= tmp && dis[0][i] < mn) mn = dis[0][i], p = i;
		if (!p) { puts("NIE"); continue; }
		dfs(p, 0, 0, 3);
		bool flag = 1; rep(i, 1, m) if (dis[3][a[i]] + dis[3][b[i]] > d[i]) { flag = 0; break; }
		if (flag) printf("TAK %d\n", p); else puts("NIE");
	}
	return 0;
}
posted @ 2018-03-02 16:28  aziint  阅读(302)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.