1. 程式人生 > >[BZOJ3251]樹上三角形

[BZOJ3251]樹上三角形

Time Limit: 10 Sec
Memory Limit: 128 MB

Description
給定一大小為 n n 的有點權樹,每次詢問一對點 ( u , v

) (u,v) ,問是否能在 u u v v 的簡單路徑上取三個點權,以這三個權值為邊長構成一個三角形。同時還支援單點修改。
Input

第一行兩個整數 n q n、q 表示樹的點數和運算元
第二行 n n 個整數表示 n
n
個點的點權
以下 n 1 n-1 行,每行2個整數 a b a、b ,表示a是b的父親(以1為根的情況下)
以下 q q 行,每行3個整數 t a b t、a、b
t = 0 t=0 ,則詢問 ( a , b ) (a,b)
t = 1 t=1 ,則將點 a a 的點權修改為 b b
n , q < = 100000 n,q<=100000 ,點權範圍 [ 1 , 2 31 1 ] [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

題解:
以前應該是在FJ省選做過這題…
對於詢問,lca查詢兩點之間的路徑長度,由於能使得他們無法組成三角形的路徑上的點權序列 g g 排序後要滿足 g [ i ] + g [ i + 1 ] < = g [ i + 2 ] g[i]+g[i+1]<=g[i+2] ,所以點權序列增長率>=斐波那契數列,但是斐波那契數列在第 48 48 位的時候就超出 2 31 2^{31} ,那麼若路徑長度>48的時候就直接輸出"Y",否則將路徑序列弄下來排序驗證一下。
對於修改就直接暴力修改。

#include<bits/stdc++.h>
#define LiangJiaJun main
using namespace std;
int n,q;
int ne,h[100004];
int fa[100004][24],depth[100004];

struct edge{
    int to,nt;
}e[300004];
void add(int u,int v){
     e[++ne].to=v;
     e[ne].nt=h[u];
     h[u]=ne;
}
int a[100004],g[104],cnt;
void dfs(int x){
     for(int i=1;fa[fa[x][i-1]][i-1];i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
     }
     for(int i=h[x];i;i=e[i].nt){
         if(depth[e[i].to])continue;
         depth[e[i].to]=depth[x]+1;
         fa[e[i].to][0]=x;
         dfs(e[i].to);
     }
}
int lca(int u,int v){
    if(depth[u]<depth[v])swap(u,v);
    int dva=(depth[u]-depth[v]);
    for(int i=0;i<=20;i++){
        if(dva&(1<<i))u=fa[u][i];
    }
    for(int i=20;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    if(u==v)return u;
    else return fa[u][0];
}
bool check(int x,int fxy,int y){
     cnt=0;
     while(x!=fxy){
        g[++cnt]=a[x];
        x=fa[x][0];
     }
     while(y!=fxy){
        g[++cnt]=a[y];
        y=fa[y][0];
     }
     g[++cnt]=a[fxy];
     sort(g+1,g+cnt+1);
     for(int i=1;i+2<=cnt;i++){
         if(1LL*g[i]+1LL*g[i+1]>1LL*g[i+2])return 1;
     }
     return 0;
}
int w33ha(){
    ne=0;
    memset(h,0,sizeof(h));
    memset(fa,0,sizeof(fa));
    memset(depth,0,sizeof(depth));
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    depth[1]=1;
    dfs(1);
    while(q--){
        int t,x,y;
        scanf("%d%d%d",&t,&x,&y);
        if(t==0){
            int fxy=lca(x,y);
            if(depth[x]+depth[y]-(depth[fxy]<<1)>48){
                puts("Y");
            }
            else{
                if(check(x,fxy,y))puts("Y");
                else puts("N");
            }
        }
        if(t==1){
            a[x]=y;
        }
    }
    return 0;
}
int LiangJiaJun(){
    while(scanf("%d%d",&n,&q)!=EOF)w33ha();
    return 0;
}