雅礼2017 WC模拟(1.21) :看门人(长链剖分)

本文介绍了一种使用长链剖分解决特定树形结构上路径查询问题的方法。通过预处理将树分解为一系列长链,使得对于任意节点,可以高效地计算其子树中满足条件的路径最小权值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:
给一棵树,边长度为1且带有权值,每个点有[li,ri][li,ri] ,求其子树中经过他的长度在[li,ri][li,ri]的路径的权值的最小值。
(n1e6)(n≤1e6)
题解:

要求O(nlogn)O(nlog⁡n),可以使用长链剖分解决。

因为每条长链独立,所以总的合并深度只有O(n)O(n), 加上区间最值,时间复杂度为O(nlogn)O(nlog⁡n)

#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;
typedef long long LL;
const int N=1e6+50,RLEN=1<<18|1,base=23333,mod=998244353;
const LL INF=0x3f3f3f3f3f3f3f;
inline char nc() {
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?-1:*ib++;
}
inline int rd() {
    char ch=nc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch==-1) return 0; if(ch=='-')f=-1; ch=nc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
    return i*f;
}

int n,mxd[N],L[N],R[N],son[N];
LL dis[N],ans[N];
vector <pii> edge[N];
struct node {
    node *lc,*rc;
    int sze,pri;
    LL mxv,v;
    inline void upt() {
        sze=lc->sze+rc->sze+1;
        mxv=max(v,max(lc->mxv,rc->mxv));
    }
}Pool[N],*pool=Pool,*rt[N],*null=Pool;
inline node* newnode(LL v) {
    ++pool;
    pool->lc=pool->rc=null;
    pool->mxv=pool->v=v;
    pool->sze=1;
    pool->pri=rand();
    return pool;
}

inline void dfs(int x,int f) {
    for(auto e:edge[x]) {
        int v=e.first, w=e.second;
        if(v==f) continue;
        dis[v]=dis[x]+w; dfs(v,f);
        if(mxd[v]+1>mxd[x]) mxd[x]=mxd[v]+1, son[x]=v;
    }
}

inline void lturn(node* &x) {
    node *ls=x->lc, *rs=ls->rc;
    x->lc=rs; x->upt();
    ls->rc=x; ls->upt();
    x=ls;
}
inline void inc(node* &x,node *t) {
    if(x==null) {x=t; return;}
    inc(x->lc,t); x->upt();
    if(x->lc->pri>x->pri) lturn(x);
}

inline LL ask(node *x,int l,int r,int L,int R) {
    if(x==null) return -INF;
    if(L<=l&&r<=R) {return x->mxv;}
    int mid=l+x->lc->sze; LL rs=-INF;
    if(R<=mid) {
        rs=max(rs,ask(x->lc,l,mid-1,L,R));
        if(R==mid) rs=max(rs,x->v);
    } else if(L>=mid) {
        rs=max(rs,ask(x->rc,mid+1,r,L,R));
        if(L==mid) rs=max(rs,x->v);
    } else {
        rs=max(rs,ask(x->lc,l,mid-1,L,R));
        rs=max(rs,ask(x->rc,mid+1,r,L,R));
        rs=max(rs,x->v);
    }
    return rs;
}
inline void modify(node *x,int l,int r,int pos,LL v) {
    int mid=l+x->lc->sze;
    if(mid==pos) x->v=max(x->v,v);
    else if(mid>pos) {
        modify(x->lc,l,mid-1,pos,v);
    } else modify(x->rc,mid+1,r,pos,v);
    x->upt();
}
node* stk[N]; int tl;
inline void travel(node *x) {
    if(x==null) return;
    travel(x->lc);
    stk[++tl]=x;
    travel(x->rc);
}
inline void dfs2(int x,int f) {
    ans[x]=-INF;
    if(son[x]) {
        dfs2(son[x],x);
        rt[x]=rt[son[x]];
        if(L[x]<=rt[x]->sze)
            ans[x]=max(ans[x],ask(rt[x],1,rt[x]->sze,L[x],min(R[x],rt[x]->sze))-dis[x]);
    }
    inc(rt[x],newnode(dis[x]));
    for(auto e:edge[x]) {
        int v=e.first; if(v==f || v==son[x]) continue;
        dfs2(v,x); 
        tl=0; travel(rt[v]);
        for(int i=1;i<=tl;i++) {
            int l=L[x]-i, r=R[x]-i;
            if(r>=0 && l<rt[x]->sze)
                ans[x]=max(ans[x], ask(rt[x],0,rt[x]->sze-1,max(l,0),min(r,rt[x]->sze-1))+stk[i]->v-2*dis[x]);
        }
        for(int i=1;i<=tl;i++)
            modify(rt[x],0,rt[x]->sze-1,i,stk[i]->v);
    }
}
int main() {
    n=rd(); null->mxv=-INF;
    for(int i=1;i<=n;i++) L[i]=rd(), R[i]=rd(), rt[i]=null;
    for(int i=2;i<=n;i++) {
        int f=rd(), w=rd();
        edge[f].push_back(pii(i,w));
    }
    dfs(1,0); dfs2(1,0);
    int pw=1,rs=0;
    for(int i=n;i>=1;i--) {
        int v;
        if(ans[i]>-INF) v=(ans[i]%mod+mod)%mod;
        else v=mod-1;
        rs=(rs+(LL)pw*v)%mod;
        pw=(LL)pw*base%mod;
    }
    printf("%d\n",rs);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值