LGP10241 [THUSC 2021] 白兰地厅的西瓜 学习笔记

LGP10241 [THUSC 2021] 白兰地厅的西瓜 学习笔记

Luogu Link

题意简述

给定一棵 \(n\) 个结点的树,每个结点有一个点权 \(a_i\)。问树上最长的LIS的长度。

\(n\le 10^5\)

做法解析

树上的任何一条简单路径显然可以被拆成最多两条直链。所以这题里面我们肯定是要把树DFS一遍,然后从下到上慢慢合并什么东西。

更新LIS包含路径最高点的答案比较显然,你用线段树合并的时候就是上升链顶比 \(a_u\) 小,下降链顶比 \(a_u\) 大的两条长度各自的最大值之和加个 \(1\)

LIS不包含路径最高点的答案怎么办呢?你在线段树合并操作的过程中做。因为你的线段树是个值域线段树,所以一个结点两个儿子分别存的直链肯定是可以接上的。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=2e5+5;
int N,A[MaxN],X,Y,ans,V=1e9+10;
vector<int> Tr[MaxN];
void addudge(int u,int v){
    Tr[u].push_back(v);
    Tr[v].push_back(u);
}
struct DynaSegTrees{
    int ncnt,rt[MaxN],ls[MaxN<<5],rs[MaxN<<5];
    struct node{
        int f,g;node(){f=g=0;}node(int x,int y){f=x,g=y;}
        friend node operator|(node &a,node &b){node c;c.f=max(a.f,b.f),c.g=max(a.g,b.g);return c;}
        friend node& operator|=(node &a,node b){a=a|b;return a;}
    }t[MaxN<<5];
    void inse(int &u,int cl,int cr,int dd,int x,int typ){
        if(!u)u=++ncnt;t[u]|={typ==1?x:0,typ==2?x:0};if(cl==cr)return;
        int cmid=(cl+cr)>>1;dd<=cmid?inse(ls[u],cl,cmid,dd,x,typ):inse(rs[u],cmid+1,cr,dd,x,typ);
    }
    void merge(int &u1,int u2){
        if(!u1){u1=u2;}if(!(u1^u2)||!u2)return;
        maxxer(ans,t[ls[u1]].f+t[rs[u2]].g);
        maxxer(ans,t[ls[u2]].f+t[rs[u1]].g);
        t[u1]|=t[u2];merge(ls[u1],ls[u2]),merge(rs[u1],rs[u2]);
    }
    node query(int u,int cl,int cr,int dl,int dr){
        if(dl<=cl&&cr<=dr)return t[u];
        int cmid=(cl+cr)>>1;node res;
        if(dl<=cmid)res|=query(ls[u],cl,cmid,dl,dr);
        if(dr>cmid)res|=query(rs[u],cmid+1,cr,dl,dr);
        return res;
    }
}DTs;
int &trg(int i){return DTs.rt[i];}
void dfs(int u,int f){
    int sl=0,sr=0;
    for(auto v : Tr[u]){
        if(v==f)continue;dfs(v,u);
        int cl=DTs.query(trg(v),0,V,0,A[u]-1).f;
        int cr=DTs.query(trg(v),0,V,A[u]+1,V).g;
        maxxer(sl,cl),maxxer(sr,cr);
        maxxer(ans,DTs.query(trg(u),0,V,A[u]+1,V).g+cl+1);
        maxxer(ans,DTs.query(trg(u),0,V,0,A[u]-1).f+cr+1);
        DTs.merge(trg(u),trg(v));
    }
    DTs.inse(trg(u),0,V,A[u],sr+1,2);
    DTs.inse(trg(u),0,V,A[u],sl+1,1);
}
int main(){
    readi(N);
    for(int i=1;i<=N;i++)readi(A[i]);
    for(int i=1;i<N;i++)readis(X,Y),addudge(X,Y);
    dfs(1,0),writi(ans);
    return 0;
}

反思总结

树上的LIS。好公式化啊。

posted @ 2025-07-07 17:28  矞龙OrinLoong  阅读(6)  评论(0)    收藏  举报