lgoj3398

题目

链接

LGOJ3398-仓鼠找sugar

题意简述

给定一棵 个节点的树,以及 个询问树上两条简单路径是否有交。

思路

LCA

简单的求出两个起点和两个终点路径的和。
与两条简单路径大小比较。
在纸上乱搞出来的,不会证。

时间复杂度:$O(nlogn)$

代码

LCA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

#define REG register
#define IN inline
#define For(x,y,z) for (REG int (x) = (y); (x) <= (z); ++(x))
#define FOR(x,y,z) for (REG int (x) = (y); (x) < (z); ++(x))
const int kmax_num = 1e5 + 10, kmax_int = INT_MAX, kmod = 1e9 + 7;

int n, q;

struct {
int v, next;
} edges[kmax_num * 2];

int cnt, head[kmax_num];

inline void AddEdge(const int& u, const int& v) {
edges[++cnt] = (Edge) {v, head[u]};
head[u] = cnt;
edges[++cnt] = (Edge) {u, head[v]};
head[v] = cnt;
return ;
}

int dep[kmax_num];
int f[33][kmax_num];

inline void GetDepth(const int& u, REG int depth) {
dep[u] = depth;
for(REG int i = head[u]; i; i = edges[i].next) {
if(!dep[edges[i].v]) GetDepth(edges[i].v, depth + 1), f[0][edges[i].v] = u;
}
return ;
}

int lg[kmax_num];

inline void Init() {
FOR(i,2,kmax_num) lg[i] = lg[i - 1] + (1 << lg[i - 1] + 1 == i);

for(REG int i = 1; (1 << i) <= n; ++i) {
For(h,1,n) f[i][h] = f[i - 1][f[i - 1][h]];
}
return ;
}

inline int LCA(REG int x, REG int y) {
if(dep[x] < dep[y]) std::swap(x, y);
while(dep[x] != dep[y])
x = f[lg[dep[x] - dep[y]]][x];

if(x == y) return x;

for(REG int i = lg[dep[x]]; i >= 0; --i)
if(f[i][x] != f[i][y])
x = f[i][x], y = f[i][y];
return f[0][x];
}

inline int GetDist(const int& x, const int& y) {
REG int anc = LCA(x, y);
return dep[x] + dep[y] - (dep[anc] << 1);
}

int main() {
std::cin >> n >> q;

int u, v;
FOR(i,1,n) {
AIOS::file_io >> u >> v;
AddEdge(u, v);
}
GetDepth(1, 1); Init();

int a, b, c, d;
For(i,1,q) {
AIOS::file_io >> a >> b >> c >> d;
if(GetDist(a, b) + GetDist(c, d) >= GetDist(a, c) + GetDist(b, d)) puts("Y");
else puts("N");
}
return 0;
}

杂项

  • 正确性不会证明(逃)。