【第三站】末日时在做什么?有没有空?可以来拯救吗?题解

· · 个人记录

这题欢迎各位用线段树、分块、平衡树、带修莫队吊打std!

题目大概就是让我们维护两个操作:区间和,区间加。

不过,看看数据范围就知道,这题用不到什么平衡树、带修莫队之类的毒瘤数据结构啦\(^o^)/!

骗分大法:Subtask#1

由于题目中说过了为样例1,直接输出样例1即可。

#include<bits/stdc++.h>
using namespace std;
int main(){
    cout<<"11"<<endl;
    cout<<"8"<<endl;
    cout<<"20"<<endl;
    return 0;
}

骗分效果不咋地,得 10 分。

正解:

#include<bits/stdc++.h>         //万能头最棒!QwQ
using namespace std;
int a[10005];                    //原数组
int main(){
    int n,m;
    scanf("%d%d",&n,&m);        //输入 n,m
    for(int i=1;i<=n;i++){      //输入数组 a
        scanf("%d",&a[i]);
    }
    while(m--){                 //for(int i=1;i<=m;i++)的偷懒写法
        int cmd=0,x=0,y=0,k=0;          
        scanf("%d",&cmd);       //输入操作编号
        if(cmd==1){             //如果是1,那么意思是把区间[x,y]内的数加上k。
            scanf("%d%d%d",&x,&y,&k);       //输入x,y,k
            for(int i=x;i<=y;i++){          //暴力在区间[x,y]内遍历每个数
                a[i]+=k;                    //每一个数都加上k
            }
        }
        else{                   //如果不是一,那么意思是查询区间[x,y]内所有数的和。
            scanf("%d%d",&x,&y);            //输入x,y
            int ans=0;                      //查询结果,记得初始化为0
            for(int i=x;i<=y;i++){          //暴力在区间[x,y]内遍历每个数
                ans+=a[i];                  //把查询结果加上a[i]
            }
            printf("%d\n",ans);             //输出查询结果,记得换行
        }
    }
    return 0;                   //完结撒花
}

有趣的东西:

此题分块做法(自己写的):

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#define ll long long
#define kkk 500005
using namespace std;
ll a[kkk],sum[kkk],sumr[kkk],f[kkk];
int sq,n,q;
ll min(ll r,ll s){
    return r<s?r:s;
}
void change(ll l,ll r,ll k){
    for(int i=l;i<=min(f[l]*sq,r);i++){
        a[i]+=(ll)k;
        sum[f[i]]+=(ll)k;
    }
    for(int i=f[l]+1;i<=f[r]-1;i++){
        sum[i]+=(ll)k*sq;
        sumr[i]+=(ll)k;
    }
    if(f[l]!=f[r]){
        for(int i=(f[r]-1)*sq+1;i<=r;i++){
            a[i]+=(ll)k;
            sum[f[i]]+=(ll)k;
        }
    }
}
ll query(ll l,ll r){
    ll ans=0;
    for(int i=l;i<=min(f[l]*sq,r);i++){
        ans+=(ll)a[i]+sumr[f[i]];
    }
    for(int i=f[l]+1;i<=f[r]-1;i++){
        ans+=(ll)sum[i];
    }
    if(f[l]!=f[r]){
        for(int i=(f[r]-1)*sq+1;i<=r;i++){
            ans+=(ll)a[i]+sumr[f[i]];
        }
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>q;
    sq=sqrt(n);
    for(int i=1;i<=n;i++){
        f[i]=(i-1)/sq+1;
        cin>>a[i];
        sum[f[i]]+=a[i];
    }
    while(q--){
        int cmd,l,r,k;
        cin>>cmd;
        switch(cmd){
            case 1:{
                cin>>l>>r>>k;
                change(l,r,k);
                break;
            }
            case 2:{
                cin>>l>>r;
                ll tmp=query(l,r);
                cout<<tmp<<endl;
                break;
            }
        }
    }
    return 0;
}

此题线段树做法:

#include<bits/stdc++.h>
#pragma GCC optimize(3)
#pragma GCC optimize(2)
using namespace std;
long long n,m,in[250],f;
struct node{
    long long l,r,sum,lz;
}t[1000];
void build(long long i,long long l,long long r){
    t[i].l=l,t[i].r=r;
    if (t[i].l==t[i].r){
        t[i].sum=in[l];
        return;
    }
    long long mid=(l+r)>>1;
    build((i<<1),l,mid);
    build((i<<1)+1,mid+1,r);
    t[i].sum=t[(i<<1)].sum+t[(i<<1)+1].sum;
}
void push_down(long long i){
    if (t[i].lz!=0){
        t[(i<<1)].lz+=t[i].lz;
        t[(i<<1)+1].lz+=t[i].lz;
        long long mid=(t[i].l+t[i].r)>>1;
        t[(i<<1)].sum+=t[i].lz*(mid-t[(i<<1)].l+1);
        t[(i<<1)+1].sum+=t[i].lz*(t[(i<<1)+1].r-mid);
        t[i].lz=0;
    }
}
long long search(long long i,long long l,long long r){
    if (t[i].l>=l&&t[i].r<=r) return t[i].sum;
    if (t[i].r<l||t[i].l>r) return 0;
    push_down(i);
    long long s=0;
    if (t[(i<<1)].r>=l) s+=search((i<<1),l,r);
    if (t[(i<<1)+1].l<=r) s+=search((i<<1)+1,l,r);
    return s;
} 
void add(long long i,long long l,long long r,long long k){
    if (t[i].l>=l&&t[i].r<=r){
        t[i].sum+=k*(t[i].r-t[i].l+1);
        t[i].lz+=k;
        return;
    }
    if (t[i].l>r||t[i].r<l) return;
    push_down(i);
    long long mid=(l+r)>>1;
    if (t[(i<<1)].r>=l) add((i<<1),l,r,k);
    if (t[(i<<1)+1].l<=r) add((i<<1)+1,l,r,k);
    t[i].sum=t[(i<<1)].sum+t[(i<<1)+1].sum;
}
int main(){
    scanf("%lld %lld",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld",&in[i]);
    build(1,1,n);
    while (m--){
        long long f,x,y,k;
        scanf("%lld",&f);
        switch(f){
            case 1:
                scanf("%lld %lld %lld",&x,&y,&k);
                add(1,x,y,k);
                break;
            case 2:
                scanf("%lld %lld",&x,&y);
                printf("%lld\n",search(1,x,y));
                break;
        }
    }
    return 0;
}

(感谢@翼德天尊提供线段树解法,%%%)

差分做法:

#include <iostream>

using namespace std;

int n, m, num[2333], cf[114514], l, r, k, opt, sum;

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(register int i = 1; i <= n; i++)
        cin >> num[i];
    for(register int i = 1; i <= n; i++)
        cf[i] = num[i] - num[i - 1];
    for(register int i = 1; i <= m; i++)
    {
        cin >> opt;
        if(opt == 1)
        {
            cin >> l >> r >> k;
            cf[l] += k, cf[r + 1] -= k;
        }
        else
        {
            cin >> l >> r;
            sum = 0;
            for(register int j = 1; j <= n; j++)
                num[j] = cf[j] + num[j - 1];
            for(register int j = l; j <= r; j++)
                sum += num[j];
            cout << sum << endl;
        }
    }
    return 0;
}

(感谢@__VAN♂游戏__提供差分做法,%%%)

平衡树做法:

等一下哈,本蒟蒻正在打(

带修莫队做法:

等一下哈,本蒟蒻正在打(