bzoj3251

3251: 树上三角形

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 637  Solved: 262
[Submit][Status][Discuss]

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

这道题很脑洞。。。首先点权的范围不超过int,如果我们想构造一个序列,正好任意三个构不成三角形,则数列是这个样子的:f[n+2]=f[n+1]+f[n] 这就是斐波那契数列,n在50左右就爆int了,所以

当n>50说明肯定是满足的,直接输出Y,否则暴力判断是否存在

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 200010
struct edge
{
    int to,nxt;
}e[N];
int n,q,cnt=1;
int dep[N],head[N];
ll key[N];
int fa[N][30];
inline bool cp(ll x,ll y)
{
    return x<y;
}
inline void link(int u,int v)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;
}
inline void change(int a,int b) { key[a]=b;}
inline void dfs(int u,int last)
{
    for(int i=head[u];i;i=e[i].nxt) if(e[i].to!=last)
    {
        int v=e[i].to;
        fa[v][0]=u;
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}
inline int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=22;i>=0;i--)
        if((dep[u]-dep[v])&(1<<i)) u=fa[u][i];
    if(u==v) return u;
    for(int i=22;i>=0;i--) if(fa[u][i]!=fa[v][i])
    {
        u=fa[u][i]; v=fa[v][i];     
    }
    return fa[u][0];
}
inline void query(int a,int b)
{
    int x=lca(a,b);
    if(dep[a]+dep[b]-2*dep[x]+1>50) 
    {
        puts("Y");
        return;
    }
    vector<ll> num; num.clear();
    for(int p=a;p!=x;p=fa[p][0]) num.push_back(key[p]);
    for(int p=b;p!=x;p=fa[p][0]) num.push_back(key[p]);
    num.push_back(key[x]);
    if(num.size()<3) 
    {
        puts("N");
        return;
    }
    sort(num.begin(),num.end(),cp);
    for(int i=0;i<num.size()-2;i++) if(num[i]+num[i+1]>num[i+2])
    {
        puts("Y");
        return;
    } 
    puts("N");
}
 
int main()
{
    memset(fa,-1,sizeof(fa));
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&key[i]);
    for(int i=1;i<n;i++) 
    {
        int u,v; scanf("%d%d",&u,&v);
        link(u,v); link(v,u);
    }
    dfs(1,0);
    for(int i=1;i<=22;i++)
        for(int j=1;j<=n;j++) if(fa[j][i-1]!=-1)
            fa[j][i]=fa[fa[j][i-1]][i-1];
    while(q--)
    {
        int opt,a,b; scanf("%d%d%d",&opt,&a,&b);
        if(opt==0) query(a,b);
        if(opt==1) change(a,b);
    }
    return 0;
}
View Code

 

posted @ 2017-02-05 09:41  19992147  阅读(169)  评论(0编辑  收藏  举报