树上三角形

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

这题直接暴力!!!

考虑一下不能凑出三角形的木棍长度排列

1,2,3,5,8,11,...

就是Fibonacci数列,所以路径长度>50就直接输出Y,否则暴力判断。。。

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1;char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e5;
vector<ui>vec;
int v[N+10];
struct S1{
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot;
    int deep[N+10],fa[N+10],Rem[N+10],top[N+10],size[N+10];
    void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    void insert(int x,int y){join(x,y),join(y,x);}
    void dfs(int x){
        deep[x]=deep[fa[x]]+1,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x,dfs(son);
            size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void build(int x){
        if (!x) return;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        build(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]||son==Rem[x])    continue;
            build(son);
        }
    }
    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]];
        }
        return deep[x]<deep[y]?x:y;
    }
    bool work(int x,int y){
        int lca=Lca(x,y);
        if (deep[x]+deep[y]-2*deep[lca]+1>50)   return 1;
        vec.clear(); vec.push_back(v[lca]);
        for (;x!=lca;x=fa[x])   vec.push_back(v[x]);
        for (;y!=lca;y=fa[y])   vec.push_back(v[y]);
        sort(vec.begin(),vec.end());
        for (vector<ui>::iterator i=vec.begin();i!=vec.end();i++)
            for (vector<ui>::iterator j=i+1;j!=vec.end();j++)
                for (vector<ui>::iterator k=j+1;k!=vec.end();k++)
                    if (*k<*j+*i)   return 1;
        return 0;
    }
}HLD;//Heavy Light Decomposition
int main(){
    int n=read(),m=read();
    for (int i=1;i<=n;i++)  v[i]=read();
    for (int i=1;i<n;i++){
        int x=read(),y=read();
        HLD.insert(x,y);
    }
    HLD.dfs(1),HLD.build(1);
    for (int i=1;i<=m;i++){
        int type=read(),x=read(),y=read();
        if (type==0)    printf(HLD.work(x,y)?"Y\n":"N\n");
        if (type==1)    v[x]=y;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Wolfycz/p/9994289.html

时间: 2024-10-28 14:17:34

树上三角形的相关文章

【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 Output 对每个询问输出一行表示答案,

树上三角形(斐波那契数列神奇应用)

树上三角形(斐波那契数列神奇应用) Description给定一个大小为 n 的有点权树,需要支持两个操作.0:询问(u,v),能否在 u 到 v 的简单路径上取三个点,使这三个点的点权作为边长可以构成一个三角形.1:修改某个点的点权. Input第一行两个整数 n,q 表示树的点数和操作数.第二行 n 个整数表示 n 个点的初始的点权.接下来 n-1 行,每行两个整数 a,b,表示 a 是 b 的父亲.接下来 q 行,每行三个整数 op,a,b:若 op=0,则表示询问(a,b).若 op=1

BZOJ 3251 树上三角形 暴力

题目大意:给定一棵树,每个点上有点权,多次修改点权,以及查询两点间路径上所有点权之间能否找出三个值构成三角形的三边长 被逗了- - 首先考虑如果一些数不能构成三角形的三边长,那么这些数最多有多少个? 显然当这些数构成斐波那契数列的时候数值的个数最多- - 那么2^31以内共有多少个斐波那契数?46! 也就是说当两点间路径上的点>=47时答案一定是YES! 那么小于47时只要暴力就行- - 时间复杂度O(mlogk) 其中k是最大的数的大小- - #include <cstdio> #in

【bzoj3251】树上三角形 朴素LCA+暴力

题目描述 给定一大小为n的有点权树,每次询问一对点(u,v),问是否能在u到v的简单路径上取三个点权,以这三个权值为边长构成一个三角形.同时还支持单点修改. 输入 第一行两个整数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 输出 对每个询问输出一行表示答案,“Y”表示有解,“N”表示无解. 样例输入 5 5 1 2

BZOJ3251 树上三角形

一看这题...难道要链剖乱搞什么的吗...不会啊汗... 突然发现不构成三角形的条件其实非常苛刻,由斐波那契数列: 1,1,2,3,5,8,13,21,34...... 可以知道其实小于int的大概就50项的样子. 于是路径长度>50直接输出'Y',否则排序判断... 看来还是蛮快的... 1 /************************************************************** 2 Problem: 3251 3 User: rausen 4 Langu

bzoj3251: 树上三角形(思维题)

神tmWA了8发调了20min才发现输出没回车T T... 首先考虑一段什么样的序列才会是N... 显然最长的形式就是斐波那契,前两数之和等于第三数之和,这样就无法组成三角形并且序列最长.可以发现在int范围内斐波那契数列不会超过50个,所以如果这段路径上节点数超过50个直接输出Y,否则把50个数拉出来排序暴力找是否有三角形就好了. #include<iostream> #include<cstring> #include<cstdlib> #include<cs

BZOJ 3251 树上三角形

NOIP的东西回成都再说吧... 这题暴力. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 100500 #define maxe 200500 using namespace std; int n,q,x,y,z,val[maxv],anc[maxv][20],dis[maxv],g[maxv],nume=0; int s[max

忧桑三角形,调了半天,真忧桑TAT

忧桑三角形 试题描述 小J是一名文化课选手,他十分喜欢做题,尤其是裸题.有一棵树,树上每个点都有点权,现在有以下两个操作: 1. 修改某个点的点权 2. 查询点u和点v构成的简单路径上是否能选出三个点组成三角形 输入 第一行两个整数N,Q,代表点数和询问数.第二行N个整数表示点权.下面N-1行每行两个整数a,b代表a,b之间有一条边.下面Q行每行3个整数t,a,b:若t=0,询问(a,b):否则将点a的权值修改为b 输出 对于每个询问输出Y表示能构成三角形,输出N表示不能构成三角形 输入示例 5

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include