洛谷 P5889 跳树(线段树)

 

 

 

 题目对于二叉树的知识点的考察直接拉满

其实很容易发现对于只有 1,3 的序列是很容易维护的,但是同时要维护右儿子,需要清楚到底要维护什么

设当前序列已经有 x 个有效的右儿子,(有效的意思是没有被访问父节点的操作抵消掉)

那么其对答案的贡献值应该是 2^{x}

剩下的就是找到有多少个有效的右儿子即可,由于这个序列会构成一棵树

那么树的根,也就是深度最低的那个节点开始才记录有效的右儿子,不仅仅是右儿子,还有左儿子

既然要维护树的根,不妨将维护这个序列转化为维护树的根,与树的右子树的深度

这样 1,3 和 2 操作就联系了起来

树的数据成员有 : top 根的高度,cnt 右儿子的贡献,down 右子树的深度

建树的时候判断序列的值给对应的树赋值即可

更新操作为基本的线段树单点更新

询问操作比较麻烦,需要将多个序列的信息进行整合,当两个序列进行整合时:

  • 如果当前序列的右子树的深度大于带加入序列根的深度时 : 那么只能抵消其右子树的一部分
  • 否则当前序列的根节点的深度要更新,且右子树完全变为带加入序列的右子树

题目还要注意,带单点更新时,此节点的信息必须完全删除后再进行更新,因为更新节点的信息并不是可覆盖的

​​​​​​​

const int N=5e5+5;

    int i,j,k;
    int n,m;
    int a[N];
    struct Node
    {
        //int l,r;
        int top,down; //树的根,树的右子树的最大深度
        int cnt; //右儿子的贡献
        #define lson id<<1
        #define rson id<<1|1
        Node(int a=0,int b=0,int c=0):top(a),down(b),cnt(c){}
        //比较两棵树 b 是否能改变原树的右子树
        Node operator + (const Node b)
        {
            Node ans;
            if(b.top>=down){ //b 可以消除 a 区间顶点右子树的影响
                ans=b;
                ans.top=b.top-down+top;
            } else{
                ans.top=top;
                ans.down=down+b.down-b.top;
                ans.cnt=((cnt>>b.top)<<b.down)+b.cnt;
            }
            return ans;
        }
        void update(int x)
        {
            //不需要判 x 是否合法,题目已明确数据范围
            top=down=cnt=0;
            x==3?top=1:down=1,cnt=(x==2);
        }
    }t[N<<2];

void push_up(int id)
{
    t[id]=t[lson]+t[rson];
}

void build(int l,int r,int id)
{
    //t[id].l=l,t[id].r=r;
    //t[id].top=t[id].down=0;
    if(l==r){
        t[id].update(a[l]);
        //dbg(t[id].top);
        //dbg(t[id].down);
    }
    else{
        int mid=l+r>>1;
        build(l,mid,lson);
        build(mid+1,r,rson);
        push_up(id);
    }
}

void update(int pos,int val,int id,int l,int r)
{
    //int l=t[id].l,r=t[id].r;
    if(l==r) t[id].update(val);
    else{
        int mid=l+r>>1;
        if(mid>=pos) update(pos,val,lson,l,mid);
        else update(pos,val,rson,mid+1,r);
        push_up(id);
    }
}

Node query(int l,int r,int id,int L,int R)
{
    //int L=t[id].l,R=t[id].r;
    if(L>=l && r>=R) return t[id];
    else{
        int mid=L+R>>1;
        Node ans;
        if(mid>=l) ans=ans+query(l,r,lson,L,mid);
        if(r>=mid+1) ans=ans+query(l,r,rson,mid+1,R);
        //dbg(ans.top);
        return ans;
    }
}

int main()
{
    //IOS;
    while(~sddd(k,n,m)){
        //k=(1<<k);
        for(int i=1;i<=n;i++) sd(a[i]);
        build(1,n,1);
        int opt,x,y;
        while(m--){
            sd(opt);
            if(opt==1){
                ll s; sll(s);
                sdd(x,y);
                Node ans=query(x,y,1,1,n);
                ll res=(max(s>>ans.top,1ll)<<ans.down)+ans.cnt;
                pll(res);
            } else{
                sdd(x,y);
                update(x,y,1,1,n);
            }
        }
    }
    //PAUSE;
    return 0;
}

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页