洛谷 P3372 【模板】线段树 1 题解

题面

题目链接:戳这里
题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:

输出包含若干行整数,即为所有操作2的结果。

输入输出样例

输入样例#1:
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出样例#1:
11
8
20

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强_,保证在int64/long long数据范围内)

样例说明:
样例说明

题解

区间修改,区间查询。

直接贴代码吧(暂时没空写思路,大体就是懒标记,网上不少教程)

错误历程(感兴趣的可以试着查查错, 不感兴趣大佬们直接看最后的正解即可)

第一次(10分代码)
#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=100005;
struct tree{
    ll l,r,v,laz;
}tr[maxn*4];
ll a[maxn];
#define len(x) (tr[x].r-tr[x].l+1)
ll buildtree(ll id,ll l,ll r){
    tr[id].l=l,tr[id].r=r;tr[id].laz=0;
    if(l==r){tr[id].v=a[l];return a[l];}
    ll mid=l+r>>1;
    tr[id].v=buildtree(id<<1,l,mid);
    tr[id].v+=buildtree(id<<1|1,mid+1,r);
    return tr[id].v;
}
void treeadd(ll al,ll ar,ll val,ll id){
    ll l=tr[id].l,r=tr[id].r;
    if(al>r||ar<l)return;
    if(al<=l&&ar>=r){
        tr[id].laz+=val;
        tr[id].v+=val*len(id);
        return;
    }
    treeadd(al,ar,val,id<<1);
    treeadd(al,ar,val,id<<1|1);
    tr[id].v=tr[id<<1].v+tr[id<<1|1].v;
    return ;
}
ll query(ll al,ll ar,ll id){
    ll l=tr[id].l,r=tr[id].r;
    if(al>r||ar<l)return 0;
    if(al<=l&&ar>=r)return tr[id].v;
    tr[id<<1].laz+=tr[id].laz;tr[id<<1|1].laz+=tr[id].laz;
    tr[id<<1].v+=tr[id].laz*len(id<<1);
    tr[id<<1|1].v+=(tr[id].laz*len(id<<1|1));
    tr[id].laz=0;
    ll ans=query(al,ar,id<<1);
    ans+=query(al,ar,id<<1|1);
    return ans;
}
int main(){
    ll n,m;scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    buildtree(1,1,n);
    for(ll i=0;i<m;i++){
        ll x,y,k,bb;scanf("%lld",&bb);
        switch(bb){
            case 1:{
                scanf("%lld%lld%lld",&x,&y,&k);
                treeadd(x,y,k,1);
                break;
            }
            case 2:{
                scanf("%lld%lld",&x,&y);
                printf("%d\n",query(x,y,1));
                break;
            }
        }
    }
    return 0;
}
第二次(70分代码)
#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=100005;
struct tree{
    ll l,r,v,laz;
}tr[maxn*4];
ll a[maxn];
#define len(x) (tr[x].r-tr[x].l+1)
ll buildtree(ll id,ll l,ll r){
    tr[id].l=l,tr[id].r=r;tr[id].laz=0;
    if(l==r){tr[id].v=a[l];return a[l];}
    ll mid=l+r>>1;
    tr[id].v=buildtree(id<<1,l,mid);
    tr[id].v+=buildtree(id<<1|1,mid+1,r);
    return tr[id].v;
}
void treeadd(ll al,ll ar,ll val,ll id){
    ll l=tr[id].l,r=tr[id].r;
    if(al>r||ar<l)return;
    if(al<=l&&ar>=r){
        tr[id].laz+=val;
        tr[id].v+=val*len(id);
        return;
    }
    tr[id<<1].laz+=tr[id].laz;tr[id<<1|1].laz+=tr[id].laz;
    tr[id<<1].v+=tr[id].laz*len(id<<1);
    tr[id<<1|1].v+=tr[id].laz*len(id<<1|1);
    tr[id].laz=0;
    treeadd(al,ar,val,id<<1);
    treeadd(al,ar,val,id<<1|1);
    tr[id].v=tr[id<<1].v+tr[id<<1|1].v;
    return ;
}
ll query(ll al,ll ar,ll id){
    ll l=tr[id].l,r=tr[id].r;
    if(al>r||ar<l)return 0;
    if(al<=l&&ar>=r)return tr[id].v;
    tr[id<<1].laz+=tr[id].laz;tr[id<<1|1].laz+=tr[id].laz;
    tr[id<<1].v+=tr[id].laz*len(id<<1);
    tr[id<<1|1].v+=tr[id].laz*len(id<<1|1);
    tr[id].laz=0;
    ll ans=query(al,ar,id<<1);
    ans+=query(al,ar,id<<1|1);
    return ans;
}
int main(){
    ll n,m;scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    buildtree(1,1,n);
    for(ll i=0;i<m;i++){
        ll x,y,k,bb;scanf("%lld",&bb);
        switch(bb){
            case 1:{
                scanf("%lld%lld%lld",&x,&y,&k);
                treeadd(x,y,k,1);
                break;
            }
            case 2:{
                scanf("%lld%lld",&x,&y);
                printf("%d\n",query(x,y,1));
                break;
            }
        }
    }
    return 0;
}

正解:

#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=100005;
struct tree{
    ll l,r,v,laz;
}tr[maxn*4];
ll a[maxn];
#define len(x) (tr[x].r-tr[x].l+1)
ll buildtree(ll id,ll l,ll r){
    tr[id].l=l,tr[id].r=r;tr[id].laz=0;
    if(l==r){tr[id].v=a[l];return a[l];}
    ll mid=l+r>>1;
    tr[id].v=buildtree(id<<1,l,mid);
    tr[id].v+=buildtree(id<<1|1,mid+1,r);
    return tr[id].v;
}
void treeadd(ll al,ll ar,ll val,ll id){
    ll l=tr[id].l,r=tr[id].r;
    if(al>r||ar<l)return;
    if(al<=l&&ar>=r){
        tr[id].laz+=val;
        tr[id].v+=val*len(id);
        return;
    }
    //第一次错误是因为区间加时忘记释放懒标记
    tr[id<<1].laz+=tr[id].laz;tr[id<<1|1].laz+=tr[id].laz;
    tr[id<<1].v+=tr[id].laz*len(id<<1);
    tr[id<<1|1].v+=tr[id].laz*len(id<<1|1);
    tr[id].laz=0;
    treeadd(al,ar,val,id<<1);
    treeadd(al,ar,val,id<<1|1);
    tr[id].v=tr[id<<1].v+tr[id<<1|1].v;
    return ;
}
ll query(ll al,ll ar,ll id){
    ll l=tr[id].l,r=tr[id].r;
    if(al>r||ar<l)return 0;
    if(al<=l&&ar>=r)return tr[id].v;
    tr[id<<1].laz+=tr[id].laz;tr[id<<1|1].laz+=tr[id].laz;
    tr[id<<1].v+=tr[id].laz*len(id<<1);
    tr[id<<1|1].v+=tr[id].laz*len(id<<1|1);
    tr[id].laz=0;
    ll ans=query(al,ar,id<<1);
    ans+=query(al,ar,id<<1|1);
    return ans;
}
int main(){
    ll n,m;scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    buildtree(1,1,n);
    for(ll i=0;i<m;i++){
        ll x,y,k,bb;scanf("%lld",&bb);
        switch(bb){
            case 1:{
                scanf("%lld%lld%lld",&x,&y,&k);
                treeadd(x,y,k,1);
                break;
            }
            case 2:{
                scanf("%lld%lld",&x,&y);
                //第二次错误是因为答案未用%lld输出
                printf("%lld\n",query(x,y,1));
                break;
            }
        }
    }
    return 0;
}

另注,define后面的字符串部分最好加上括号,我一开始 样例都没过 就是因为忘记加括号了然后乘法优先级高于加法,所以炸了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值