GoatGirl98 / Walkthrough-of-ACCoding-in-BUAA

北航OJ通关攻略,包括北航软件学院的在线评测网站(OJ)——AC编程(accoding.buaa.edu.cn)开放课程的全部题解

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DS = Data structure of Shawn's 做复杂了

ShawnDongWish opened this issue · comments

https://github.com/GoatGirl98/Walkthrough-of-ACCoding-in-BUAA/tree/master/%E5%85%B6%E4%BB%96%E6%AF%94%E8%B5%9B/%E7%AC%AC%E4%B8%80%E5%B1%8A%E9%98%BFShawn%E9%9D%A2%E8%AF%95%E7%AE%97%E6%B3%95%E7%AB%9E%E8%B5%9B

这题您做复杂了,我才看到这个解题报告
这题关键是,每个数字最多被除 32 次就变成 1 了,于是乎我们可以记录每一段最大值,如果 > 1 就暴力更新除法。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cassert>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int N = 1e5 + 9;
long long tmin[N << 2];
long long tsum[N << 2];
void pushUp(int rt) {
    tmin[rt] = max(tmin[rt << 1] , tmin[rt << 1 | 1]);
    tsum[rt] = tsum[rt << 1] + tsum[rt << 1 | 1];
}
void update(int p , long long c , int l , int r , int rt) {
    if (l == r) {
        tmin[rt] = c;
        tsum[rt] = c;
        return;
    }
    int m = l + r >> 1;
    if (p <= m) update(p , c , lson);
    else update(p , c , rson);
    pushUp(rt);
}
void updateD(int L , int R , long long c , int l , int r , int rt) {
    if (tmin[rt] == 0){
        return;
    }
    if (l == r) {
        tmin[rt] /= c;
        tsum[rt] /= c;
        return;
    }
    int m = l + r >> 1;
    if (L <= m) {
        updateD(L , R , c , lson);
    }
    if (m < R) {
        updateD(L , R , c , rson);
    }
    pushUp(rt);
}
long long query(int L , int R , int l , int r , int rt) {
    if (L <= l && r <= R) {
        return tsum[rt];
    }
    int m = l + r >> 1;
    long long ret = 0;
    if (L <= m) {
        ret += query(L , R , lson);
    }
    if (m < R) {
        ret += query(L , R , rson);
    }
    return ret;
}
void solve(){
    memset(tsum , 0 , sizeof(tsum));
    memset(tmin , 0 , sizeof(tmin));
    int n;
    scanf("%d" , &n);
    for (int i = 1 ; i <= n ; ++i) {
        int x;
        scanf("%d" , &x);
        update(i , x , 1 , n , 1);
    }
    int m ;
    scanf("%d" , &m);
    char op[3];
    while (m--) {
        scanf("%s" , op);
        if (op[0] == 'Q') {
            int l , r;
            scanf("%d%d" , &l , &r);
            printf("%lld\n" , query(l , r , 1 , n , 1));
        } else if (op[0] == 'D') {
            int l , r , c;
            scanf("%d%d%d" , &l , &r , &c);
            if (c == 1) continue;
            updateD(l , r , c , 1 , n , 1);
        } else if (op[0] == 'M') {
            int p , c;
            scanf("%d%d" , &p , &c);
            update(p , c , 1 , n , 1);
        } else {
            assert(0);
        }
    }
}
int main(){
    solve();
}

确实是复杂了,我这个做法是因为之前做过一道包括区间向下整除操作的题目,所以直接考虑用分段维护最值做减法,单点赋值就直接混过去了。复杂度没问题但是常数必然是大了。感谢您的指正和对题解的贡献!