由于每个操作2只会执行1次、撤销1次,操作1只有第一次回全部修改,之后都是O(1)打标记,所以不会超时。

#include <stdio.h>
#define N 200005
int n, m, i, j, k, gai, s[N], x[N], p[N];
long long a[N], c;
int main(){
    scanf("%d", &n);
    for(i=1; i<=n; i++){
        scanf("%lld", &a[i]);
    }
    scanf("%d", &m);
    for(i=1; i<=m; i++){
        scanf("%d", &s[i]);
        if(s[i] == 1){
            scanf("%d", &x[i]);
            if(gai){
                for(j=i-1; j>gai; j--){
                    if(s[j] == 3) continue;
                    a[p[j]] -= x[j];
                }
                c += x[i] - x[j], gai = i;
            }//再次赋值:撤销操作2,c记录全部需要加多少
            else{
                for(j=1; j<=n; j++) a[j] = x[i];
                c = 0, gai = i;
            }//首次赋值:O(n)初始化
        }
        if(s[i] == 2){
            scanf("%d%d", &p[i], &x[i]);
            a[p[i]] += x[i];
        }
        if(s[i] == 3){
            scanf("%d", &p[i]);
            printf("%lld\n", a[p[i]]+c);
        }
    }
    return 0;
}

xielr代码:空间换代码,代码简洁、拓展性强

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=2e5+5;
int n,m,cnt,sum;
map<int,int>a[MAXN];
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i][sum]);
    scanf("%lld",&m);
    while(m--){
        int opt,x,y;
        scanf("%lld",&opt);
        if(opt==1){
            scanf("%lld",&x);
            cnt=x;
            sum++;
        }
        else if(opt==2){
            scanf("%lld%lld",&x,&y);
            a[x][sum]+=y;
        }
        else{
            scanf("%lld",&x);
            printf("%lld\n",a[x][sum]+cnt);
        }
    }
    return 0;
}

作者 crxis

发表回复