1 条题解

  • 0
    @ 2025-8-24 22:45:54

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar EnofTaiPeople
    MGXS

    搬运于2025-08-24 22:45:54,当前版本为作者最后更新于2023-07-08 08:38:57,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Part1 前言

    省选前一直想改这道题,一直不敢,结果现在国赛模拟搬原题强制落实,被我两个小时场切了。

    启示:数据结构题还是场切更有意思。

    最近的国赛模拟频繁地出现 LCT 或 Top Tree(无一例外都场切了),可能会直接导致我重新开始研究 Top Tree,毕竟我又没有 D/E 类名额。

    Part2 问题转化

    发现将一个节点与其儿子依次合并不好做,将这棵树重构。

    每次将 AxA_xAyA_y 合并时,新建一个节点,左儿子为 xx,右儿子为 yy

    注意这时 xx 会变成新建的节点,同时记录每一个节点子树最后的合并结果为 mstxmst_x,查询时就是从 mstxmst_x 开始往下跳关于 axa_x 的带权重链。

    Part3 两个操作

    WBTT 这篇文章讲得很清楚,反正我都是学 zx2003 的。

    这篇文章里讲了两个操作,accessdrop,我们每次更改节点 xx 的权值时,先对 xx access,即强制将其到根路径上的边变为重边。

    然后进行 drop,即将不合法的重边变为轻边,具体地,记录 ltxlt_x 表示节点 xx 的重儿子带权 sizesize 减去轻儿子带权 sizesize,若 ltx0lt_x\le 0,则可能需要抖落,这样的边最多有 O(logV)O(\log V) 条。

    至于如何动态维护 ltxlt_x,只要在 access 之后链加就行了。

    Part4 一些细节

    求答案时需要向下跳重链,起初我想用倍增维护(参考 CSP-S 2019 树的重心),但这样是错误的,我白白浪费了好多时间。

    事实上,这里需要记录 clxcl_x 表示 xx 往下跳到底的答案,在带权轻重边切换时,假设是 xx 的重儿子变为 yy,我们先求出 clycl_y,再从 xx 往上(二分)跳重链,将这段重链节点的 clcl 赋值为 clycl_y

    因为每次切换 O(logn)O(\log n),每次最多 O(logV)O(\log V) 次切换,所以总时间复杂度 O(n+qlognlogV)O(n+q\log n\log V),空间 O(n)O(n)

    Part5 后记

    希望我可以从本题衍生出 WBTT 的考场可写作实现方式。

    希望 Top Tree 文化能够一直传递下去。

    才 2023 年,有的是希望。

    Upd:本题并不能衍生出 WBTT 的实现方式,因为那比这个要复杂许多,但我已经学会了复杂度严格、支持 Link-Cut 的 WBTT,却依旧无法做到 考场可写作。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4e5+5;
    using ll=long long;
    ll a[N],sm[N];
    int n,q,rt,cnt,L[N],R[N],fa[N];
    int mst[N],d[N];
    vector<int>lk[N];
    ll lt[N],mn[N],tg[N];
    int cl[N],ctg[N];
    int lc[N],sl[N];//lc[x]=1->x is'nt wtson
    int t[N][2],f[N];
    #define ls t[x][0]
    #define rs t[x][1]
    #define tp(x) (t[f[x]][1]==x)
    #define in(x) (t[f[x]][0]==x||tp(x))
    void pp(int x){
        sl[x]=sl[ls]|sl[rs]|lc[x];
        mn[x]=min({mn[ls],mn[rs],lt[x]});
    }
    void add(int x,ll d){
        tg[x]+=d,mn[x]+=d,lt[x]+=d;
    }
    void adc(int x,int c){
        cl[x]=ctg[x]=c;
    }
    void pd(int x){
        if(tg[x]){
            if(ls)add(ls,tg[x]);
            if(rs)add(rs,tg[x]);
            tg[x]=0;
        }if(ctg[x]){
            adc(ls,ctg[x]),adc(rs,ctg[x]);
            ctg[x]=0;
        }
    }
    void ppd(int x){
        if(in(x))ppd(f[x]);pd(x);
    }
    void rot(int x){
        int y=f[x],k=tp(x),w=t[x][!k];
        t[f[w]=t[x][!k]=y][k]=w;
        if(in(y))t[f[y]][tp(y)]=x;
        f[x]=f[y],f[y]=x,pp(y);
    }
    void splay(int x){ppd(x);
        for(int y=f[x];in(x);rot(x),y=f[x])
            if(in(y))rot(tp(x)^tp(y)?x:y);pp(x);
    }
    void acs(int x){
        for(int y=0;x;x=f[y=x])
            splay(x),rs=y,pp(x);
    }
    int dfs(int x){
        sort(lk[x].begin(),lk[x].end());
        int nw=x,p;sm[x]=a[x],cl[x]=x;
        for(int y:lk[x]){
            p=++cnt;
            fa[L[p]=nw]=p;
            fa[R[p]=dfs(y)]=p;
            f[L[p]]=f[R[p]]=p;
            if(sm[L[p]]>=sm[R[p]]){
                d[p]=L[p];
                lc[R[p]]=1,cl[p]=cl[L[p]];
                lt[p]=sm[L[p]]-sm[R[p]];
            }else{
                d[p]=R[p];
                lc[L[p]]=1,cl[p]=cl[R[p]];
                lt[p]=sm[R[p]]-sm[L[p]];
            }
            sm[nw=p]=sm[L[p]]+sm[R[p]];
        }return mst[x]=nw;
    }
    vector<int>nd;
    void rep(int x,int y){
        // cerr<<"rep:"<<x<<" "<<y<<endl;
        if(y!=d[x]){
            splay(d[x]),lc[d[x]]=1,pp(d[x]);
            splay(y),d[x]=y;
            int p=cl[y];
            splay(x),rs=0;
            lt[x]=-lt[x],pp(x);
            if(!lc[x])
                if(sl[ls]){
                    for(x=ls;;){
                        pd(x);
                        if(sl[rs])x=rs;
                        else if(lc[x])break;
                        else x=ls;
                    }
                }else{
                    while(ls)pd(x),x=ls;
                }
            // cerr<<x<<" "<<p<<endl;
            splay(x),cl[x]=p,adc(rs,p);
            // cerr<<cl[x]<<endl;
            splay(y),lc[y]=0,pp(y);
        }
    }
    void access(int x){
        acs(x),splay(x);
        // cerr<<x<<" "<<sl[x]<<" "<<lc[x]<<endl;
        while(x&&sl[x]){
            while(1){
                pd(x);
                if(sl[rs])x=rs;
                else if(lc[x])break;
                else x=ls;
            }splay(x);
            nd.push_back(x);
            x=ls;
        }
        for(int p:nd)
            if(p!=rt)rep(fa[p],p);
        nd.clear();
    }
    void drop(int x){
        int mast=x;
        acs(x),splay(x),x=ls,splay(x);
        while(x&&mn[x]<=0){
            while(1){
                // cout<<"tg:"<<tg[x]<<endl;
                // cout<<"*"<<x<<" "<<ls<<" "<<rs<<" "<<mn[rs]<<" "<<mn[ls]<<" "<<lt[x]<<" "<<mn[x]<<endl;
                pd(x);
                // cout<<x<<" "<<ls<<" "<<rs<<" "<<mn[rs]<<" "<<mn[ls]<<" "<<lt[x]<<" "<<mn[x]<<endl;
                if(mn[rs]<=0)x=rs;
                else if(lt[x]<=0)break;
                else x=ls;
            }
            // cerr<<x<<endl;
            splay(x);
            // cerr<<x<<endl;
            nd.push_back(x);
            x=ls;
        }
        for(int p:nd)
            if(p!=mast){
                // cerr<<p<<" "<<d[p]<<" "<<lt[p]<<endl;
                if(d[p]==L[p]){
                    // cerr<<p<<" "<<lt[p]<<endl;
                    if(lt[p]<0)rep(p,R[p]);
                }else rep(p,L[p]);
            }
        nd.clear();
    }
    int main(){
        // freopen("copy.in","r",stdin);
        // freopen("copy.out","w",stdout);
        ios::sync_with_stdio(false);
        int i,j,k,l,r,x,y;
        cin>>n>>q,cnt=n;ll d;
        mn[0]=1e18;
        for(x=1;x<=n;++x)cin>>a[x];
        for(x=2;x<=n;++x){
            cin>>y;
            lk[y].push_back(x);
        }rt=dfs(1);
        for(x=1;x<=cnt;++x)pp(x);
        // for(x=n+1;x<=cnt;++x)
        //     splay(x),printf("x:%d d:%d L:%d R:%d lt:%lld\n",x,::d[x],L[x],R[x],lt[x]);
        // for(x=1;x<=cnt;++x)
        //     printf("x:%d lc:%d\n",x,lc[x]);
        while(q--){
            cin>>k>>x;
            if(k==1){
                splay(mst[x]);
                // cerr<<cl[mst[x]]<<endl;
                printf("%lld\n",a[cl[mst[x]]]);
                // if(x==3){
                //     splay(8),printf("%lld\n",lt[8]);
                // }
            }else{
                cin>>d,access(x),a[x]+=d;
                acs(x),splay(x);
                // for(int x=1;x<=cnt;++x)
                //     printf("x:%d ls:%d rs:%d f:%d\n",x,ls,rs,f[x]);
                // printf("x:%d mn:%lld\n",x,mn[x]);
                // printf("ls:%d mn:%lld\n",ls,mn[ls]);
                add(ls,d),pp(x);
                // if(!q)exit(0);
                // printf("x:%d mn:%lld\n",x,mn[x]);
                // cout<<"drop:"<<endl;
                drop(x);
                // cout<<"end:"<<endl;
            }
            // for(x=n+1;x<=cnt;++x)
            //     splay(x),printf("x:%d d:%d L:%d R:%d lt:%lld\n",x,::d[x],L[x],R[x],lt[x]);
            // fflush(stdout);
        }return 0;
    }
    
    • 1

    信息

    ID
    8046
    时间
    2000ms
    内存
    512MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者