BZOJ3251:树上三角形(乱搞)
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
n,q<=100000,点权范围[1,2^31-1]
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
Solution
考虑对于一个询问的一个树链,如果我们自己构造,让他不含三角形我们会怎么构造:
肯定是像$1,2,3,5,8,13$一样,类似斐波那契数列。
而斐波那契又是增长非常快的,所以当询问的树链长度超过一个值(我设的$50$个点)就肯定$Y$,否则就暴力。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<algorithm> 6 #define N (100009) 7 using namespace std; 8 9 struct Edge{int to,next;}edge[N<<2]; 10 int n,q,a[N],f[N][18],Depth[N]; 11 int head[N],num_edge; 12 vector<int>v; 13 14 inline int read() 15 { 16 int x=0,w=1; char c=getchar(); 17 while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();} 18 while (c>='0' && c<='9') x=x*10+c-'0', c=getchar(); 19 return x*w; 20 } 21 22 void add(int u,int v) 23 { 24 edge[++num_edge].to=v; 25 edge[num_edge].next=head[u]; 26 head[u]=num_edge; 27 } 28 29 void DFS(int x,int fa) 30 { 31 f[x][0]=fa; Depth[x]=Depth[fa]+1; 32 for (int i=1; i<=17; ++i) 33 f[x][i]=f[f[x][i-1]][i-1]; 34 for (int i=head[x]; i; i=edge[i].next) 35 if (edge[i].to!=fa) DFS(edge[i].to,x); 36 } 37 38 int LCA(int x,int y) 39 { 40 if (Depth[x]<Depth[y]) swap(x,y); 41 for (int i=17; i>=0; --i) 42 if (Depth[f[x][i]]>=Depth[y]) x=f[x][i]; 43 if (x==y) return x; 44 for (int i=17; i>=0; --i) 45 if (f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i]; 46 return f[x][0]; 47 } 48 49 void Solve(int x,int y,int lca) 50 { 51 v.clear(); 52 while (x!=lca) v.push_back(a[x]), x=f[x][0]; 53 while (y!=lca) v.push_back(a[y]), y=f[y][0]; 54 v.push_back(a[lca]); 55 sort(v.begin(),v.end()); 56 for (int i=1,s=v.size(); i<s-1; ++i) 57 if (1ll*v[i-1]+v[i]>v[i+1]) {puts("Y"); return;} 58 puts("N"); 59 } 60 61 int main() 62 { 63 n=read(); q=read(); 64 for (int i=1; i<=n; ++i) a[i]=read(); 65 for (int i=1; i<=n-1; ++i) 66 { 67 int u=read(),v=read(); 68 add(u,v); add(v,u); 69 } 70 DFS(1,0); 71 while (q--) 72 { 73 int opt=read(),x=read(),y=read(); 74 if (opt==0) 75 { 76 int lca=LCA(x,y); 77 if (Depth[x]-Depth[lca]+Depth[y]-Depth[lca]+1>50) puts("Y"); 78 else Solve(x,y,lca); 79 } 80 else a[x]=y; 81 } 82 }