Description
给定一大小为n的有点权树,每次询问一对点(u,v),问是否能在u到v的简单路径上取三个点权,以这三个权值为边长构成一个三角形。同时还支持单点修改。
Input
第一行两个整数n、q表示树的点数和操作数
第二行n个整数表示n个点的点权
以下n-1行,每行2个整数a、b,表示a是b的父亲(以1为根的情况下)
以下q行,每行3个整数t、a、b
若t=0,则询问(a,b)
若t=1,则将点a的点权修改为b
Output
对每个询问输出一行表示答案,“Y”表示有解,“N”表示无解。
Sample Input
5 5
1 2 3 4 5
1 2
2 3
3 4
1 5
0 1 3
0 4 5
1 1 4
0 2 5
0 2 3
Sample Output
N
Y
Y
N
HINT
对于100%的数据,n,q<=100000,点权范围[1,231-1]
题解
我们发现不能构成三角形的数列为菲波那切数列(1,1,2,3,5……),所以到第47项时已经超过了Int,所以我们当点的个数大于47个时,就可以直接输出Y了。小于直接暴力。
代码
#include<bits/stdc++.h>
#define inf 10000005
#define N 100005
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int Head[N],ret[2*N],Next[2*N];
int n,q,tot,c[55],fa[N],v[N],dep[N];
void ins(int u,int v)
{
ret[++tot]=v;
Next[tot]=Head[u];Head[u]=tot;
}
void dfs(int u)
{
for (int i=Head[u];i;i=Next[i])
{
int v=ret[i];
if (v!=fa[u])
{
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v);
}
}
}
void solve(int a,int b)
{
int cnt=0;
while (cnt<50&&a!=b)
{
if (dep[a]<dep[b]) swap(a,b);
cnt++;
c[cnt]=v[a];
a=fa[a];
}
cnt++;c[cnt]=v[a];
if (cnt>=50){puts("Y");return;}
sort(c+1,c+cnt+1);
for (int i=1;i<=cnt-2;i++)
if ((ll)c[i]+c[i+1]>c[i+2]){puts("Y");return;}
puts("N");
}
int main()
{
n=read();q=read();
for (int i=1;i<=n;i++) v[i]=read();
for (int i=1;i<n;i++)
{
int u=read(),v=read();
ins(u,v);
}
dfs(1);int opt,x,y;
while (q--)
{
opt=read();x=read();y=read();
if (opt) v[x]=y;
else solve(x,y);
}
return 0;
}