BZOJ3251 树上三角形

  以传统的维护思路特别不可做。完全想不到的一点是,如果构造一个int内的数列使其中任意三个数都不能构成三角形,项数最多的方案显然是斐波拉契数列,而斐波拉契数列的项数显然是log级的。那么我们求出询问点之间的距离,如果超过项数直接输出,否则暴力判断即可。

  开始算距离的时候没把lca*2调了半天,而且明明可以暴力的为什么还写倍增啊。大概脑子坏了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define int unsigned int
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,a[N],p[N],fa[N][18],deep[N],q[61],t=0;
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k)
{
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k][0])
    {
        deep[edge[i].to]=deep[k]+1;
        dfs(edge[i].to);
    }
}
int lca(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    for (int j=17;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
    if (x==y) return x;
    for (int j=17;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj3251.in","r",stdin);
    freopen("bzoj3251.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y);fa[y][0]=x;
    }
    fa[1][0]=1;
    for (int j=1;j<18;j++)
        for (int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    dfs(1);
    while (m--)
    {
        int op=read(),x=read(),y=read();
        if (op==0)
        {
            int l=lca(x,y);
            if (deep[x]+deep[y]-(deep[l]<<1)>60) printf("Y\n");
            else
            {
                int cnt=0;
                while (x!=l) q[++cnt]=a[x],x=fa[x][0];
                while (y!=l) q[++cnt]=a[y],y=fa[y][0];
                q[++cnt]=a[l];
                sort(q+1,q+cnt+1);
                bool flag=1;
                for (int i=1;i<=cnt-2;i++)
                if (q[i]+q[i+1]>q[i+2]) {flag=0;break;}
                if (flag) printf("N\n");
                else printf("Y\n");
            }
        }
        else a[x]=y;
    }
    return 0;
}

 

posted @ 2018-09-19 20:05  Gloid  阅读(147)  评论(0编辑  收藏  举报