LGP12361 [eJOI 2024] 糖果售卖 学习笔记

LGP12361 [eJOI 2024] 糖果售卖 学习笔记

Luogu Link

前言

\(\text{cyx}\) 居然一遍过了这题吗。还是说他直接复制的标程。

题意简述

给定一棵 \(n\) 个结点的树。每个结点有两个值 \(k_u,t_u\)。“一次行动”是指:你从 \(1\) 开始朝一个选定的点 \(p\) 移动,并带着一个初始为 \(0\) 的计数器。你在处于某个点的一开始,计数器会增加 \(k_u\),然后若满足 \(t_u<k_u\),你就“满足”了点 \(u\)。不同行动间互不干扰。

\(n\) 次修改,每次对一个 \(k_u\) 单点加 \(d\)。在每次修改之后回答,当前局面下一次行动最多可能满足多少个点。

\(n,q\le 5\times 10^5\)\(0\le t_i\le 10^9\)\(1\le k_i,d\le 10^9\)

做法解析

一个点的 \(k_u\) 会对满足其子树内的点做出(可能的)贡献。一个点被满足时会对支持其子树内的点成为答案做出贡献。所以你不妨把问题视作:每次单点修(包括初始赋值)都是在对 \(k'_u\) 搞子树加,每个被满足的点都会对 \(t'_u\) 搞子树加,你输出 \(\max t'_u\) 就行了。

显然是势能线段树题。

代码实现

能写能调,状态十分唐诗。

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=5e5+5;
const lolo Inf=1e18;
int N,Q,X,T[MaxN],Y;
vector<int> Tr[MaxN];
int dfn[MaxN],dcnt,nfd[MaxN],siz[MaxN];
void dfs(int u){
    dfn[u]=++dcnt,nfd[dcnt]=u,siz[u]=1;
    for(int v : Tr[u])dfs(v),siz[u]+=siz[v];
}
struct SegTree2{
    int mx[MaxN<<2],tag[MaxN<<2];
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    void pushup(int u){mx[u]=max(mx[ls(u)],mx[rs(u)]);}
    void maketag(int u,int x){mx[u]+=x,tag[u]+=x;}
    void pushdown(int u){if(tag[u])maketag(ls(u),tag[u]),maketag(rs(u),tag[u]),tag[u]=0;}
    void update(int u,int cl,int cr,int dl,int dr,int x){
        if(dl<=cl&&cr<=dr){maketag(u,x);return;}
        pushdown(u);int cmid=(cl+cr)>>1;
        if(dl<=cmid)update(ls(u),cl,cmid,dl,dr,x);
        if(dr>cmid)update(rs(u),cmid+1,cr,dl,dr,x);
        pushup(u);
    }
}SgT2;
struct SegTree1{
    lolo mx[MaxN<<2],tag[MaxN<<2];
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    void pushup(int u){mx[u]=max(mx[ls(u)],mx[rs(u)]);}
    void build(int u,int cl,int cr){
        if(cl==cr){mx[u]=-T[nfd[cl]];return;}int cmid=(cl+cr)>>1;
        build(ls(u),cl,cmid),build(rs(u),cmid+1,cr);pushup(u);
    }
    void maketag(int u,int x){mx[u]+=x,tag[u]+=x;}
    void pushdown(int u){
        if(!tag[u])return;
        maketag(ls(u),tag[u]),maketag(rs(u),tag[u]),tag[u]=0;
    }
    void update(int u,int cl,int cr,int dl,int dr,int x){
        if(dl<=cl&&cr<=dr){maketag(u,x);return;}
        pushdown(u);int cmid=(cl+cr)>>1;
        if(dl<=cmid)update(ls(u),cl,cmid,dl,dr,x);
        if(dr>cmid)update(rs(u),cmid+1,cr,dl,dr,x);
        pushup(u);
    }
    void maxser(int u,int cl,int cr,int dl,int dr){
        if(cl==cr){
            if(mx[u]<0)return;
            SgT2.update(1,1,N,cl,cl+siz[nfd[cl]]-1,1);
            mx[u]=-Inf;return;
        }
        pushdown(u);int cmid=(cl+cr)>>1;
        if(dl<=cmid&&mx[ls(u)]>=0)maxser(ls(u),cl,cmid,dl,dr);
        if(dr>cmid&&mx[rs(u)]>=0)maxser(rs(u),cmid+1,cr,dl,dr);
        pushup(u);return;
    }
}SgT1;
int main(){
    readis(N,Q);
    for(int i=2;i<=N;i++)readi(X),Tr[X].push_back(i);
    for(int i=1;i<=N;i++)readi(T[i]);
    dfs(1);SgT1.build(1,1,N);
    for(int i=1,cans;i<=Q;i++){
        readis(X,Y);SgT1.update(1,1,N,dfn[X],dfn[X]+siz[X]-1,Y);
        SgT1.maxser(1,1,N,1,N);cans=SgT2.mx[1],writil(cans);
    }
    return 0;
}
posted @ 2025-07-20 17:34  矞龙OrinLoong  阅读(7)  评论(0)    收藏  举报