Address
Solution
正解没想出来还把 LCA 写挂了,实在太弱了。- 先考虑一种暴力,把
u→v
u
→
v
路径上所有点权取出,按从小到大排序,则我们只需要判断相邻的三个元素是否能构成三角形即可。
- 一个简单的解释:
- 假设排序完后的序列为
a1,a2,...,am
a
1
,
a
2
,
.
.
.
,
a
m
,枚举三角形的最长边
ak
a
k
。
- 那么一个合法的三角形显然满足
ai<aj<ak
a
i
<
a
j
<
a
k
且
ai+aj>ak
a
i
+
a
j
>
a
k
。
- 因为我们已经排好序了,所以
ak−2,ak−1
a
k
−
2
,
a
k
−
1
显然比
ak
a
k
小,并且它们相加的和最大。
- 暴力复杂度
O(q nlogn)
O
(
q
n
log
n
)
,考虑怎样优化。
- 根据暴力构造一组最长的不能构成三角形的序列
a1,a2,...,am
a
1
,
a
2
,
.
.
.
,
a
m
(按照从小到大排序)。
- 假定
a1=1,a2=1
a
1
=
1
,
a
2
=
1
,因为
a3≥a1+a2
a
3
≥
a
1
+
a
2
且序列要尽量长,所以
a3=a1+a2=2
a
3
=
a
1
+
a
2
=
2
- 类似的,我们发现这样构造出来的就是斐波拉契数列,即
ai=ai−1+ai−2
a
i
=
a
i
−
1
+
a
i
−
2
- 因为
1≤ai≤231−1
1
≤
a
i
≤
2
31
−
1
,序列长度最多也就47。
- 那么对于长度超过 47 的路径就可以直接输出
‘Y′
‘
Y
′
,这便是暴力的优化。
- 用倍增求 LCA 的话,时间复杂度大概是
O(qlogn)
O
(
q
log
n
)
。
Code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cctype>
using namespace std;
namespace inout
{
const int S = 1 << 20;
char frd[S], *ihed = frd + S;
const char *ital = ihed;
inline char inChar()
{
if (ihed == ital)
fread(frd, 1, S, stdin), ihed = frd;
return *ihed++;
}
inline int get()
{
char ch; int res = 0; bool flag = false;
while (!isdigit(ch = inChar()) && ch != '-');
(ch == '-' ? flag = true : res = ch ^ 48);
while (isdigit(ch = inChar()))
res = res * 10 + ch - 48;
return flag ? -res : res;
}
};
using namespace inout;
typedef long long ll;
const int N = 1e5 + 5;
int fa[N][20], a[N], val[N], dep[N];
int n, m, q;
struct Edge
{
int to; Edge *nxt;
}p[N], *T = p, *lst[N];
inline void Link(int x, int y)
{
(++T)->nxt = lst[x]; lst[x] = T; T->to = y;
}
inline void initLCA(int x, int Fa)
{
dep[x] = dep[Fa] + 1;
for (int i = 0; i < 17; ++i)
fa[x][i + 1] = fa[fa[x][i]][i];
for (Edge *e = lst[x]; e; e = e->nxt)
{
int y = e->to;
fa[y][0] = x;
initLCA(y, x);
}
}
inline int queryLCA(int x, int y)
{
if (x == y) return x;
if (dep[x] < dep[y]) swap(x, y);
for (int i = 18; i >= 0; --i)
{
if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if (x == y) return x;
}
for (int i = 18; i >= 0; --i)
if (fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int main()
{
n = get(); q = get(); int k, x, y, z;
for (int i = 1; i <= n; ++i) val[i] = get();
for (int i = 1; i < n; ++i)
{
x = get(); y = get();
Link(x, y);
}
initLCA(1, 0);
while (q--)
{
k = get(); x = get(); y = get();
if (k & 1) val[x] = y;
else
{
z = queryLCA(x, y); bool flag = false;
if (dep[x] + dep[y] - 2 * dep[z] > 46)
{
puts("Y");
continue;
}
a[m = 1] = val[z];
while (x != z) a[++m] = val[x], x = fa[x][0];
while (y != z) a[++m] = val[y], y = fa[y][0];
sort(a + 1, a + m + 1);
for (int i = 1, im = m - 2; i <= im; ++i)
if (a[i] > a[i + 2] - a[i + 1])
{
flag = true;
break;
}
puts(flag ? "Y" : "N");
}
}
return 0;
}