题目大意:给定一大小为n的有点权树,每次询问一对点(u,v),问是否能在u到v的简单路径上取三个点权,以这三个权值为边长构成一个三角形。同时还支持单点修改。
题解:看到题目果断开始想数据结构,感觉要上lct?蒟蒻表示不会……膜了一发题解后。考虑这样一个问题:有一个数列,数列中的数满足题目条件,那么最优就是斐波那契数列,在2^31次方中斐波那契数列只有不到50项……路径长度大于50直接输出,小于就暴力排序搞一下,最坏O(q*50*log50)
我的收获:猜测答案增长速度(例如指数型)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=100005;
int n,q,t;
int head[M],dep[M],fa[M],w[M],st[105];
struct edge{int to,nex;}e[M*4];
void add(int u,int v){e[t].to=v,e[t].nex=head[u],head[u]=t++;}
void dfs(int x)
{
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=fa[x]) fa[v]=x,dep[v]=dep[x]+1,dfs(v);
}
}
bool check(int x,int y)
{
int top=0,z;
while(top<47&&x!=y)
{
if(dep[x]<dep[y]) z=x,x=y,y=z;
st[++top]=w[x],x=fa[x];
}
st[++top]=w[x];
if(top>=47) return true;
sort(st+1,st+1+top);
for(int i=3;i<=top;i++)
if(st[i-1]>st[i]-st[i-2])//用减法防止爆int
return true;
return false;
}
void work()
{
int x,y,opt;
while(q--)
{
scanf("%d%d%d",&opt,&x,&y);
if(!opt) puts(check(x,y)?"Y":"N");
else w[x]=y;
}
}
void init()
{
cin>>n>>q;t=0;
int x,y;memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1);
}
int main()
{
init();
work();
return 0;
}