BZOJ3251: 树上三角形
生活随笔
收集整理的這篇文章主要介紹了
BZOJ3251: 树上三角形
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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 51 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
NY
Y
N 題解Here! 首先容易想到一個暴力算法: 若詢問是x,y,求出LCA(x,y),暴力將這條鏈中所有的點權存入數組,排個序,暴力掃一遍。 也就是這樣: bool solve(int x,int y){int lca=LCA(x,y);int top=0,num[100010];num[++top]=val[lca];for(int i=x;i!=lca;i=fa[i])num[++top]=val[i];for(int i=y;i!=lca;i=fa[i])num[++top]=val[i];sort(num+1,num+top+1);if(top<3)return false;for(int i=3;i<=top;i++)if(num[i]<num[i-1]+num[i-2])return true;return false; }
但是不用想就知道肯定TLE。。。
怎么辦?
我們注意到點權是231以內的數,而判斷條件是兩邊之和大于第三邊。
兩邊之和大于第三邊!
跟某一個式子很像:f[i]=f[i-1]+f[i-2]
這是什么?斐波那契數列!
在231以內,數列的最大項只達到了50項。
也就是說:超過50項,一定存在3個數可以組成三角形!
所以,我們在函數頭部添加一句:
if(deep[x]+deep[y]-2*deep[lca]>=50)return true;即可。
注意:由于點權是231以內,所以要將判斷組成三角形的式子移個項,不然會爆int。
附代碼:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 100010 using namespace std; int n,m,c=1; int val[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],top[MAXN]; struct node{int next,to; }a[MAXN<<1]; inline int read(){int date=0,w=1;char c=0;while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}return date*w; } inline void add(int x,int y){a[c].to=y;a[c].next=head[x];head[x]=c++;a[c].to=x;a[c].next=head[y];head[y]=c++; } void dfs1(int rt){son[rt]=0;size[rt]=1;for(int i=head[rt];i;i=a[i].next){int will=a[i].to;if(!deep[will]){deep[will]=deep[rt]+1;fa[will]=rt;dfs1(will);size[rt]+=size[will];if(size[son[rt]]<size[will])son[rt]=will;}} } void dfs2(int rt,int f){top[rt]=f;if(son[rt])dfs2(son[rt],f);for(int i=head[rt];i;i=a[i].next){int will=a[i].to;if(will!=fa[rt]&&will!=son[rt])dfs2(will,will);} } int LCA(int x,int y){while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]])swap(x,y);x=fa[top[x]];}if(deep[x]>deep[y])swap(x,y);return x; } bool solve(int x,int y){int lca=LCA(x,y);if(deep[x]+deep[y]-2*deep[lca]>=50)return true;int top=0,num[55];num[++top]=val[lca];for(int i=x;i!=lca;i=fa[i])num[++top]=val[i];for(int i=y;i!=lca;i=fa[i])num[++top]=val[i];sort(num+1,num+top+1);if(top<3)return false;for(int i=3;i<=top;i++)if(num[i]-num[i-1]<num[i-2])return true;return false; } void work(){int f,x,y;while(m--){f=read();x=read();y=read();if(f==0){if(solve(x,y))printf("Y\n");else printf("N\n");}if(f==1)val[x]=y;} } void init(){int x,y;n=read();m=read();for(int i=1;i<=n;i++)val[i]=read();for(int i=1;i<n;i++){x=read();y=read();add(x,y);}deep[1]=1;dfs1(1);dfs2(1,1); } int main(){init();work();return 0; }?
轉載于:https://www.cnblogs.com/Yangrui-Blog/p/9097139.html
總結
以上是生活随笔為你收集整理的BZOJ3251: 树上三角形的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js表单验证(提示版)
- 下一篇: Visio软件方案UML选择