题目链接:BZOJ 3251
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
Y
Y
N
分析
只要在一条路径上找到三个数,使他们成为三角形就好
因为找不到三个数成三角形的条件太苛刻了
对任意三个数a1,a2,a3必须满足a1+a2<=a3
按从小到大排列这些数,发现他们的增长是很快的
最接近三角形的就是大小相邻的三个数
取等时不就是斐波那契嘛
那在47项的时候就爆int了
哦,47个数以上的,就必定会有三个数成三角形
over
有的时候正向不好想可以反向来
注意条件苛刻的地方,往往就是突破口
代码
1 /***************************** 2 User:Mandy.H.Y 3 Language:c++ 4 Problem:Triangle 5 *****************************/ 6 //一剑霜寒十四州 7 #include<bits/stdc++.h> 8 #define Max(x,y) ((x) > (y) ? (x) : (y)) 9 #define Min(x,y) ((x) < (y) ? (x) : (y)) 10 11 using namespace std; 12 13 const int maxn = 1e5 + 5; 14 15 int n,q,size; 16 long long val[maxn]; 17 int father[maxn],dep[maxn]; 18 int first[maxn],cnt[maxn]; 19 int top[maxn]; 20 long long cur[maxn]; 21 22 struct Edge{ 23 int v,nt; 24 }edge[maxn << 1]; 25 26 template<class T>inline void read(T &x){ 27 x = 0;bool flag = 0;char ch = getchar(); 28 while(!isdigit(ch)) flag |= ch == '-',ch = getchar(); 29 while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar(); 30 if(flag) x = -x; 31 } 32 33 template<class T>void putch(const T x){ 34 if(x > 9) putch(x / 10); 35 putchar(x % 10 | 48); 36 } 37 38 template<class T>void put(const T x){ 39 if(x < 0) putchar('-'),putch(-x); 40 else putch(x); 41 } 42 43 void file(){ 44 freopen("Triangle.in","r",stdin); 45 freopen("Triangle.out","w",stdout); 46 } 47 48 void eadd(int u,int v){ 49 edge[++size].v = v; 50 edge[size].nt = first[u]; 51 first[u] = size; 52 } 53 54 void readdata(){ 55 read(n);read(q); 56 for(int i = 1;i <= n; ++ i) read(val[i]); 57 for(int i = 1;i < n; ++ i){ 58 int u,v; 59 read(u);read(v); 60 eadd(u,v); 61 father[v] = u; 62 } 63 } 64 65 void dfs(int u){ 66 top[u] = u; 67 int son = 0,mcnt = 0; 68 cnt[u] = 1; 69 for(int i = first[u];i;i = edge[i].nt){ 70 int v = edge[i].v; 71 dep[v]=dep[u]+1; 72 dfs(v); 73 cnt[u] += cnt[v]; 74 if(cnt[v] > mcnt){ 75 mcnt = cnt[v]; 76 son = v; 77 } 78 } 79 if(son) top[son] = u; 80 } 81 82 int find(int x){ 83 return top[x] == x ? x : top[x] = find(top[x]); 84 } 85 86 int LCA(int x,int y){ 87 if(find(x) == find(y)) return dep[x] < dep[y] ? x : y; 88 else return dep[top[x]] < dep[top[y]] ? LCA(x,father[top[y]]) : LCA(y,father[top[x]]); 89 } 90 91 void work(){ 92 dep[1] = 1; 93 dfs(1); 94 while(q--){ 95 int t; 96 read(t); 97 if(t == 0) { 98 int a,b; 99 read(a);read(b); 100 int anc = LCA(a,b); 101 int num = dep[a]+dep[b]-(dep[anc]<<1)+1; 102 if(num > 50) puts("Y"); 103 //一个三角形都没有的条件是很苛刻的 104 //任意三个数中,较小的两个数的和必须小于等于最大的数 105 //这种数列最长应该是斐波那契 106 //而斐波那契在47项就爆int了 107 else{ 108 int tot = 0,fa = a; 109 while(fa != anc){ 110 cur[++tot] = val[fa]; 111 fa = father[fa]; 112 } 113 fa = b; 114 while(fa != anc){ 115 cur[++tot] = val[fa]; 116 fa = father[fa]; 117 } 118 bool judge = 0; 119 cur[++tot] = val[anc]; 120 sort(cur + 1,cur + 1 + tot); 121 for(int i = 3;i <= tot; ++ i){ 122 if(cur[i] < cur[i-1]+cur[i-2]) { 123 puts("Y"); 124 judge = 1; 125 break; 126 } 127 } 128 if(!judge) puts("N"); 129 } 130 } else { 131 long long a,b; 132 read(a);read(b); 133 val[a] = b; 134 } 135 } 136 } 137 138 int main(){ 139 // file(); 140 readdata(); 141 work(); 142 return 0; 143 }