[BZOJ3251]树上三角形

版权声明:辛辛苦苦码字,你们转载的时候记得告诉我 https://blog.csdn.net/dxyinme/article/details/83661136

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;
}

猜你喜欢

转载自blog.csdn.net/dxyinme/article/details/83661136