bzoj3251
3251: 树上三角形
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 637 Solved: 262
[Submit][Status][Discuss]
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
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
Y
Y
N
HINT
对于100%的数据,n,q<=100000,点权范围[1,231-1]
Source
这道题很脑洞。。。首先点权的范围不超过int,如果我们想构造一个序列,正好任意三个构不成三角形,则数列是这个样子的:f[n+2]=f[n+1]+f[n] 这就是斐波那契数列,n在50左右就爆int了,所以
当n>50说明肯定是满足的,直接输出Y,否则暴力判断是否存在
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define N 200010 struct edge { int to,nxt; }e[N]; int n,q,cnt=1; int dep[N],head[N]; ll key[N]; int fa[N][30]; inline bool cp(ll x,ll y) { return x<y; } inline void link(int u,int v) { e[++cnt].nxt=head[u]; head[u]=cnt; e[cnt].to=v; } inline void change(int a,int b) { key[a]=b;} inline void dfs(int u,int last) { for(int i=head[u];i;i=e[i].nxt) if(e[i].to!=last) { int v=e[i].to; fa[v][0]=u; dep[v]=dep[u]+1; dfs(v,u); } } inline int lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); for(int i=22;i>=0;i--) if((dep[u]-dep[v])&(1<<i)) u=fa[u][i]; if(u==v) return u; for(int i=22;i>=0;i--) if(fa[u][i]!=fa[v][i]) { u=fa[u][i]; v=fa[v][i]; } return fa[u][0]; } inline void query(int a,int b) { int x=lca(a,b); if(dep[a]+dep[b]-2*dep[x]+1>50) { puts("Y"); return; } vector<ll> num; num.clear(); for(int p=a;p!=x;p=fa[p][0]) num.push_back(key[p]); for(int p=b;p!=x;p=fa[p][0]) num.push_back(key[p]); num.push_back(key[x]); if(num.size()<3) { puts("N"); return; } sort(num.begin(),num.end(),cp); for(int i=0;i<num.size()-2;i++) if(num[i]+num[i+1]>num[i+2]) { puts("Y"); return; } puts("N"); } int main() { memset(fa,-1,sizeof(fa)); scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&key[i]); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); link(u,v); link(v,u); } dfs(1,0); for(int i=1;i<=22;i++) for(int j=1;j<=n;j++) if(fa[j][i-1]!=-1) fa[j][i]=fa[fa[j][i-1]][i-1]; while(q--) { int opt,a,b; scanf("%d%d%d",&opt,&a,&b); if(opt==0) query(a,b); if(opt==1) change(a,b); } return 0; }