题意:一个n个点的树,询问某两点之间的简单路径,问路径上任选三边能否组成一个三角形。 N<100000,权值<109
思路:
这里最神奇的思路过于以下这个:
n个数,任意三个都不能组成三角形,只有当:
排序A,且A[i] >= A[i-1] + A[i-2];
观察可以发现其增长类似斐波那契,又因为权值<109,所以当路径里边的个数>=45个时,必然可以组成三角形。
剩下的,就暴力一下就好了。
确定路径边的个数的方法是深度结合lca来做。暴力的话就是两点向上攀,直到公共祖先。然后sort一下,然后检查是否存在 A[i] < A[i-1] + A[i-2]就好了。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 100010 struct BCJ{ int fa[N]; void init(int n) { for (int i = 0; i <= n; i++) fa[i] = i; } void unin(int u, int v) { fa[find(v)] = find(u); } int find(int u) { return fa[u] == u? fa[u] : fa[u] = find(fa[u]); } }comFa; struct faEdge{ int fa; int c; }fa[N]; int dep[N]; struct Graph{ struct Edge{ int to, next, c; }e[N<<2]; int head[N]; int p; void init(){ memset(head, -1, sizeof(head)); p = 0; } void add(int u, int v, int len) { e[p].to = v; e[p].c = len; e[p].next = head[u]; head[u] = p++; } }g, q; struct Query{ int s,t,com; }que[N]; void dfs(int now) { //printf("now = %d ", now); for (int i = g.head[now]; ~i; i = g.e[i].next) { int &to = g.e[i].to; //printf("to = %d ", to); if (dep[to] == -1) { dep[to] = dep[now]+1; fa[to].fa = now; fa[to].c = g.e[i].c; dfs(to); comFa.unin(now,to); } } for (int i = q.head[now]; ~i; i = q.e[i].next) { int &to = q.e[i].to; if (dep[to] != -1) { que[q.e[i].c].com = comFa.find(to); } } } int a[N]; int main() { int n; while (scanf("%d", &n) != EOF) { g.init(); for (int i = 0; i < n-1; i++) { int a, b, len; scanf("%d%d%d", &a, &b, &len); g.add(a,b,len); g.add(b,a,len); } int m; scanf("%d", &m); q.init(); for (int i = 0; i < m; i++) { int s, t; scanf("%d%d", &s, &t); que[i].s = s; que[i].t = t; q.add(s,t,i); q.add(t,s,i); } memset(dep, -1, sizeof(dep)); dep[1] = 0; fa[1].fa = 1; fa[1].c = 0; comFa.init(n); dfs(1); for (int i = 0; i < m; i++) { int nodeNum = dep[que[i].s] + dep[que[i].t] - 2*dep[que[i].com]; if (nodeNum >= 45) { puts("Yes"); } else { int top = 0; for (int j = que[i].s; j != que[i].com; j = fa[j].fa) { a[top++] = fa[j].c; } for (int j = que[i].t; j != que[i].com; j = fa[j].fa) { a[top++] = fa[j].c; } sort(a,a+top); bool ok = false; for (int i = 2; i < top; i++) { if (a[i] < a[i-1]+a[i-2]) { ok = true; break; } } puts(ok?"Yes":"No"); } } } return 0; }