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

对于100%的数据,n,q<=100000,点权范围[1,231-1]

Source

路径上节点个数大于50直接输出Y否则暴力..
zky学长当时是这么讲的…至于为什么?
引自黄学长blog:

若路径上有两点的点权为x,y
则若有个点z且z > abs(x-y)且z < x+y,则可以构成三角形
类似斐波那契数列1 2 3 5 8 13 。。。
发现最好情况下int范围只有不到50个点满足无法构成三角形
那么只要路径点超过50个直接输出Y,否则暴力

就是这样

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define MAXN 100100
using namespace std;
int n,q,top,Top;
int deep[MAXN],fa[MAXN],sta[MAXN],val[MAXN];
struct edge
{
    int to;
    edge *next;
}e[MAXN<<1],*prev[MAXN];
void insert(int u,int v)
{
    e[++Top].to=v;e[Top].next=prev[u];prev[u]=&e[Top];
}
void in(int &x)
{
    char ch=getchar();x=0;int flag=1;
    while (!(ch>='0'&&ch<='9')) flag=ch=='-'?-1:flag,ch=getchar();
    while (ch>='0'&&ch<='9')    x=x*10+ch-'0',ch=getchar();x*=flag;
}
void dfs(int x)
{
    for (edge *i=prev[x];i;i=i->next)   deep[i->to]=deep[x]+1,fa[i->to]=x,dfs(i->to);
}
void query(int a,int b)
{
    top=0;
    while (top<50&&a!=b)
    {
        if (deep[a]>deep[b])    sta[++top]=val[a],a=fa[a];
        else    sta[++top]=val[b],b=fa[b];
    }
    sta[++top]=val[a];
    if (top>=50)    {puts("Y");return;}
    sort(sta+1,sta+top+1);
    for (int i=1;i<top-1;i++)
        if ((LL)sta[i]+sta[i+1]>sta[i+2])   {puts("Y");return;}
    puts("N");
}
int main()
{
    in(n);in(q);
    for (int i=1;i<=n;i++)  in(val[i]);
    for (int i=1;i<n;i++)
    {
        int u,v;in(u);in(v);insert(u,v);
    }
    dfs(1);
    for (int i=1;i<=q;i++)
    {
        int opt,u,v;in(opt);in(u);in(v);
        if (!opt)   query(u,v);
        else    val[u]=v;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值