1. 程式人生 > >[XSY 1158] Triangle

[XSY 1158] Triangle

path 左右 spa left clu sts esp 暴力 getchar()

題意

  給定一棵 $n$ 個節點的樹, 每條邊有邊權 $w$ .

  $m$ 組詢問 $(x, y)$ : 求 $path(x, y)$ 上的所有邊權中, 是否能夠找出三條, 組成三角形.

  $n \le 100000$ .

分析

  不妨設權值的集合為 $\left\{ a_1, a_2, ..., a_k \right\}(a_1 \le a_2 \le ... \le a_k)$ .

  如果存在三條, 那麽一定 $\exists i \in [1, k-2], a_i + a_{i+1} > a_{i+2}$ .

  也就是說, 暴力判定的復雜度是 $O(k \log k)$ .

  我們嘗試找到更多性質, 來更好的求解這個問題.

  假設組成不了三角形, 那麽要求 $a_{i+2} \ge a_i + a_{i+1}$ , 而增長最慢的情況是 $a_{i+2} = a_i + a_{i+1}$ .

  但這樣已經夠快了, 是斐波那契數列.

  所以只要超出 50 項左右, 就一定有解.

實現

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <vector>
using
namespace std; #define F(i, a, b) for (register int i = (a); i <= (b); i++) const int N = 200005; int n, m; struct Edge { int v, d, nx; inline Edge(int _v = 0, int _d = 0, int _nx = 0): v(_v), d(_d), nx(_nx) {} }mp[N]; int tot, hd[N]; int par[N], dep[N], w[N]; int s[N], top; inline int rd(void
) { int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1; int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f; } inline void Ins(int u, int v, int d) { mp[++tot] = Edge(v, d, hd[u]), hd[u] = tot; } void Prework(int x) { for (int k = hd[x]; k > 0; k = mp[k].nx) if (mp[k].v != par[x]) { par[mp[k].v] = x, dep[mp[k].v] = dep[x]+1, w[mp[k].v] = mp[k].d; Prework(mp[k].v); } } int main(void) { #ifndef ONLINE_JUDGE freopen("xsy1158.in", "r", stdin); freopen("xsy1158.out", "w", stdout); #endif for (int nT = rd(), t = 1; t <= nT; t++) { tot = 0, memset(hd, 0, sizeof hd); n = rd(); F(i, 1, n-1) { int u = rd(), v = rd(), d = rd(); Ins(u, v, d), Ins(v, u, d); } memset(par, 0, sizeof par), memset(dep, 0, sizeof dep), memset(w, 0, sizeof w); Prework(1); printf("Case #%d:\n", t); m = rd(); F(i, 1, m) { int u = rd(), v = rd(); for (top = 0; top <= 50 && u != v; ) dep[u] > dep[v] ? (s[++top] = w[u], u = par[u]) : (s[++top] = w[v], v = par[v]); if (top > 50) puts("Yes"); else { bool done = false; sort(s+1, s+top+1); for (int j = 1; j+2 <= top && !done; j++) if (s[j] + s[j+1] > s[j+2]) done = true, puts("Yes"); if (!done) puts("No"); } } } return 0; }

[XSY 1158] Triangle