【bzoj3251】树上三角形

6 篇文章 0 订阅
6 篇文章 0 订阅

曾经有一题,给一棵树,每次询问一些链,这条链上是否存在满足三角形不等式的边权。
如果这条链不满足的话,那么对于任意a[i]+a[i+1]都有<=a[j]。然后这个东西最朴素情况就是斐波那契数列。数据又很小,所以如果一条链长度大于50就肯定存在了。
至于这题……就只是多了个修!改!点!权!
非常脑残地写了lct 23333333
要是我出题肯定来个真*动态树上三角形,支持链、子树删除加入什么的2333333

#include <bits/stdc++.h>
using namespace std;
#define For(i,a,b) for(int i=a;i<=b;i++)
#define maxn 100007

inline int rd() {
    char c = getc(stdin);
    while (!isdigit(c)) c = getc(stdin) ; int x = c - '0';
    while (isdigit(c = getc(stdin))) x = x * 10 + c - '0';
    return x;
}

int a[maxn] , tot , val[maxn] , n , q;

struct LCT {

    int ch[maxn][2] , sz[maxn] , fa[maxn] , s[maxn] , top , rev[maxn];

    #define lc ch[u][0]
    #define rc ch[u][1]

    inline bool isrt(int u) { return ch[fa[u]][0] != u && ch[fa[u]][1] != u ; }

    inline void mt  (int u) { sz[u] = 1 + (lc ? sz[lc] : 0) + (rc ? sz[rc] : 0) ; }

    inline void rv  (int u) { swap(lc , rc) , rev[lc] ^= 1 , rev[rc] ^= 1 ; }

    inline void ps  (int u) { if (u && rev[u]) rv(u) , rev[u] = 0 ; }

    inline void cr  (int u) {
        s[top ++] = u;
        for(;!isrt(u);u = fa[u]) s[top ++] = fa[u];
        while (top) ps(s[-- top]);
    }

    inline void rot(int u) {
        int f = fa[u] , g = fa[f] , l , r;
        l = (ch[f][1] == u) , r = l ^ 1 ;
        if (!isrt(f)) ch[g][ch[g][1] == f] = u;
        fa[u] = g , fa[f] = u;if (ch[u][r]) fa[ch[u][r]] = f;
        ch[f][l] = ch[u][r] , ch[u][r] = f;
        mt(f) , mt(u);
    }

    void splay(int u) {
        for(cr(u);!isrt(u);rot(u)) {
            int f = fa[u] , g = fa[f];
            if (!isrt(f)) rot(((ch[f][0] == u) ^ (ch[g][0] == f)) ? u : f);
        }
        mt(u);
    }

    void access(int u) {
        int v = u;
        for(int t = 0;u;t = u , u = fa[u])
            splay(u) , rc = t ;
        splay(v);
    }

    void mkrt(int u) { access(u) ; rev[u] ^= 1 ; ps(u) ; }

    void link(int u , int v) { mkrt(u) , fa[u] = v , access(u) ; }

    void split(int u , int v) { mkrt(u) , access(v); }

    int  get_dis(int u , int v) {
        split(u , v);
        return sz[v];
    }

    void travel(int u) {
        a[++ tot] = val[u];
        if (lc) travel(lc);
        if (rc) travel(rc);
    }

}T;

void input() {
    n = rd() , q = rd();
    For(i , 1 , n) val[i] = rd() , T.sz[i] = 1;
    For(i , 2 , n) T.link(rd() , rd());
}

bool query(int u , int v) {
    int d = T.get_dis(u , v);
    if (d >= 50) return 1;
    tot = 0 , T.travel(v);
    sort(a + 1 , a + tot + 1);
    For(i , 1 , tot - 2) if ((long long)a[i] + a[i + 1] > a[i + 2]) return 1;
    return 0;
}

void solve() {
    For(i , 1 , q) {
        int t = rd() , u = rd() , v = rd();
        if (t) val[u] = v;
        else puts(query(u , v)?"Y":"N");
    }
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
    #endif
    input();
    solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值