10pts求调,谢谢各位

P3372 【模板】线段树 1

pumpkin_porridge @ 2024-09-15 15:24:12

(我这开点有点浪费空间)

#include<iostream>

using namespace std;

int m,n;
int a[100004];

struct SegTreeNode
{
    int lran,rran,val,tag_add;
    SegTreeNode *left,*right;

    SegTreeNode()=default;
    SegTreeNode(int l,int r):lran(l),rran(r),tag_add(0),left(nullptr),right(nullptr)
    {
        val=0;
        for(int i=lran;i<=rran;i++) val+=a[i];
    }
    ~SegTreeNode()
    {
        if(left) {delete left; left=nullptr;}
        if(right) {delete right; right=nullptr;}
    }
    void check()
    {
        if(!left && lran!=rran) left=new SegTreeNode(lran,(lran+rran)/2);
        if(!right && lran!=rran) right=new SegTreeNode((lran+rran)/2+1,rran);
    }

    void pushdown()
    {
        if(!tag_add) return;
        if(lran==rran)
        {
            tag_add=0;return;
        }
        check();
        left->tag_add += tag_add;
        right->tag_add += tag_add;
        left->val += tag_add * (left->rran - left->lran + 1);
        right->val += tag_add * (right->rran - right->lran +1);
        tag_add=0;
    }

};

struct SegTree
{
    SegTreeNode *root;

    SegTree()=default;
    SegTree(int l,int r)
    {
        root=new SegTreeNode(l,r);
    }
    ~SegTree()
    {
        delete root;
        root=nullptr;
    }

    void add(SegTreeNode *node,int x,int y,int k)
    {
        if(x==node->lran && y==node->rran)
        {
            node->tag_add+=k;
            node->val+=k*(node->rran - node->lran +1);
            return;
        }//lran=rran already returns here
        int mid = (node->lran + node->rran)/2;
        node->check();
        if(y<=mid)
        {
            add(node->left,x,y,k);
        }
        else if(x>=mid+1)
        {
            add(node->right,x,y,k);
        }
        else
        {
            add(node->left,x,mid,k);
            add(node->right,mid+1,y,k);
        }
        node->val = node->left->val + node->right->val;
    }

    int sum(SegTreeNode *node,int x,int y)
    {
        if(x==node->lran && y==node->rran) return node->val;//lran==rran already returns here
        int mid=(node->lran + node->rran)/2;
        node->check();
        node->pushdown();
        if(y<=mid)
        {
            return sum(node->left,x,y);
        }
        else if(x>=mid+1)
        {
            return sum(node->right,x,y);
        }
        else
        {
            return sum(node->left,x,mid) + sum(node->right,mid+1,y);
        }
    }
};

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];

    SegTree Tree(1,n);

    for(int i=1;i<=m;i++)
    {
        int op,x,y,k;
        cin>>op;
        if(op==1)
        {
            cin>>x>>y>>k;
            Tree.add(Tree.root,x,y,k);
        }
        if(op==2)
        {
            cin>>x>>y;
            cout<<Tree.sum(Tree.root,x,y)<<endl;
        }
    }
    return 0;
}

by pumpkin_porridge @ 2024-09-15 15:41:32

查了一圈,并未找到动态开点+真实指针的代码,自己尝试模仿传统代码又失败了,望大佬给点帮助


by Hagasei @ 2024-09-15 15:49:12

@pumpkin_porridge add 里没 pushdown


by Hagasei @ 2024-09-15 15:51:15

不过确实不是很建议这么写,堆式存储的线段树只需要十多行


by pumpkin_porridge @ 2024-09-15 17:47:01

还是有点不明白,仅在查询过程中进行即时的pushdown为什么不能保证该查询路径上节点信息都没有问题?@Hagasei


by Hagasei @ 2024-09-16 12:01:10

@pumpkin_porridge 对不起没看luogu,不在修改时 pushdown 会使修改在 pushup 时左右儿子的val不对,进而导致这一条链的val都失效,而如果只查询到标记节点的祖先结果就错了。可能说的有点抽象你尝试理解一下


by pumpkin_porridge @ 2024-09-19 08:56:15

(我也好久没看洛谷了) 感谢,可以理解了 @Hagasei


|