BZOJ 3251 树上三角形

题目链接: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

Sample Output

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 }
View Code

 

posted @ 2019-09-11 11:48  Mandy_H_Y  阅读(108)  评论(0编辑  收藏