不错的题,想了挺久的。
不妨把点1设为根节点。
对于每个限制,到达ai→bi这条路径的距离一定不大于某个数,在根节点确定的情况下,第i个限制的距离最大就是max{0,dist[ai]+dist[bi]−di2}以内,其中dist表示该点到根节点的距离。
这就可以转化成类似一堆已知某个端点的线段求某个交点的问题。
于是先取限制距离最大的线段上的点,然后一路往上跑直到某个点刚好满足限制,对于这个点再判断一下是否满足所有情况即可,总复杂度O(n+m)。
参考了一下zimpha的写法。
看了下AMPPZ的官方solution似乎有O(n+mlogn)的做法,然而并不能看懂(波兰语)2333。
然而不知道为什么跑得超级超级超级慢QAQ
(唔memset太多次了?)
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define fore(i,u) for(int i=head[u];i;i=nxt[i])
#define cr(x) memset(x , 0 , sizeof x)
#define maxn 300007
#define maxm 600007
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
typedef int arr[maxn];
typedef int adj[maxm];
arr head , dis , fa , a , b , d;
adj to , nxt;
int n , m , ett;
inline void add(int u , int v) {
to[++ ett] = v , nxt[ett] = head[u] , head[u] = ett;
}
inline void ins(int u , int v) {
add(u , v) , add(v , u);
}
void input() {
n = rd() , m = rd();
ett = 0 , cr(head);
rep(i , 2 , n) ins(rd() , rd());
rep(i , 1 , m) a[i] = rd() , b[i] = rd() , d[i] = rd();
}
void dfs(int u) {
fore(i , u) {
int v = to[i];
if (v == fa[u]) continue;
dis[v] = dis[u] + 1 , fa[v] = u , dfs(v);
}
}
void solve() {
int u = 1;
rep(times , 1 , 2) {
dis[u] = 0 ; cr(fa) ; dfs(u);
int rec_d = 0 , rec_u = 0;
rep(i , 1 , m) {
int t = (dis[a[i]] + dis[b[i]] - d[i] + 1) / 2;
if (rec_d < t) rec_d = t , rec_u = a[i];
}
if (!rec_d) {
printf("TAK\n%d\n" , u);
return ;
}
u = rec_u;
rep(i , 1 , dis[rec_u] - rec_d) u = fa[u];
}
puts("NIE");
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
per(T , rd() , 1) {
input();
solve();
}
return 0;
}