70分求助

P3372 【模板】线段树 1

Zxx20120715 @ 2024-05-22 18:41:45

#include<iostream>
using namespace std;
const int maxn=100010;
int n,m,a[maxn];
struct node//线段树的一个节点 
{
    //第一个需要修改的地方:增加维护的值 
    int l,r;//这段区间的左端点、右端点
    int sum;//这段区间的和
    int minv;//这段区间的最小值 
    int tag;//懒标记
    //代表当前节点所对应的区间 每一个数都被加了tag
    //但是 这件事还没有告诉当前节点的两个儿子 
    node(){
        //第二个需要修改的地方:增加维护的值的初始化 
        l=r=sum=tag=minv=0;
    } 
}z[maxn*4];//z[i]代表线段树的第i个节点

#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

node operator+(const node &l,const node &r)//定义线段树如何合并两个区间 
{
    //第三个需要修改的地方:增加维护的值 计算方法 
    node res;

    res.l=l.l; res.r=r.r;
    res.sum = l.sum + r.sum;
    res.minv = min(l.minv,r.minv);

    return res;
}

void build(int l,int r,int rt)//当前的线段树节点编号为rt 其所对应的区间为l~r
//建立这棵线段树 
{
    if (l==r)//走到了最下面 区间只有一个数 那就建立这个节点 
    {
        //第四个需要修改的地方:长度为1的区间这个值怎么处理 
        z[rt].l=z[rt].r=l;
        z[rt].sum = a[l];
        z[rt].minv=a[l];
        return;
    }
    int m=(l+r)>>1;//从l~r中间砍开 l~m作为左儿子区间 m+1~r作为右儿子区间
    build(lson);//build(l,m,rt<<1);//build(l,m,rt*2);//建立左儿子 
    build(rson);//build(m+1,r,rt<<1|1);//build(m+1,r,rt*2+1);//建立右儿子 
    z[rt] = z[rt<<1] + z[rt<<1|1];
} 

void color(int rt,int v)//给节点rt打一个+v的懒标记
{
    //第五个需要修改的地方:增加维护的值的打标记方法 
    z[rt].sum += v * (z[rt].r-z[rt].l+1);
    z[rt].tag += v;
    z[rt].minv += v;
} 

void push_col(int rt)//把节点rt的标记告诉它的儿子
{
    if (z[rt].tag != 0)
    {
        color(rt<<1,z[rt].tag);
        color(rt<<1|1,z[rt].tag);
        z[rt].tag=0;
    }
} 

node query(int l,int r,int rt,int nowl,int nowr)//logn
//当前线段树节点为l~r,编号为rt 此时要询问nowl~nowr这段区间
{
    if (nowl<=l && r<=nowr) return z[rt];//l~r当前线段树节点所对应的区间被询问区间完全包含
    push_col(rt);//把懒标记下放 
    int m=(l+r)>>1; 
    if (nowl<=m)//询问区间和左儿子有交 
    {
        if (m<nowr)//询问区间和右儿子有交
            return query(lson,nowl,nowr) + query(rson,nowl,nowr);
        else//代表只和左儿子有交
            return query(lson,nowl,nowr); 
    }
    else//只和右儿子有交
        return query(rson,nowl,nowr); 
} 

void modify(int l,int r,int rt,int nowl,int nowr,int v)
//当前线段树节点编号为rt 区间为l~r
//修改操作为给nowl~nowr这段区间整体+v
{
    if (nowl<=l && r<=nowr) {//当前区间被修改区间整体包含 
        color(rt,v);//给节点rt打一个整体+v的懒标记
        return; 
    }
    push_col(rt);//把懒标记下放 
    int m=(l+r)>>1;
    if (nowl<=m) modify(lson,nowl,nowr,v);//修改区间和左儿子有交 
    if (m<nowr) modify(rson,nowl,nowr,v);//修改区间和右儿子有交
    z[rt] = z[rt<<1] + z[rt<<1|1]; 
} 

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

    build(root);//建树 
    for (int i=1;i<=m;i++)
    {
        int opt;
        cin >> opt;
        if (opt==1)//修改操作
        {
            int x,y,k;
            cin >> x >> y >> k;
            modify(root,x,y,k);
        }
        else//询问操作 
        {
            int x,y;
            cin >> x >> y;
            cout << query(root,x,y).sum << endl;
        } 
    }

    return 0;
}

这位蒟蒻在 #8 #9 #10 WA,求助。


by 迟暮天复明 @ 2024-05-22 19:01:32

兄弟你没开ll


by Zxx20120715 @ 2024-05-22 19:07:45

@迟暮天复明 已 AC 十分感谢!


|