建立多个树状数组

链接:https://www.nowcoder.com/acm/contest/112/D
来源:牛客网

题目描述

一个只含数字的字符串,q次操作,每次操作将第i位数字改为x,每次操作后,统计长度在[l, r]之间且首数字大于尾数字的子串的个数。

输入描述:

第一行一个只含数字的字符串;
第二行3个整数q, l, r;
接下来q行,每行两个整数i, x。

输出描述:

输出q行,每行一个整数,表示长度在[l, r]之间且首数字大于尾数字的子串的个数。
示例1

输入

585605
2 2 4
1 6
4 2

输出

7
8

备注:

设字符串长度为n则:
1 <= n <= 100000;
1 <= q <= 100000; 1 <= l <= r <= n; 1 <= i <= n; 0 <= x<= 9;


思路分析 :
  对每一个数字建立树状数组,然后每次更新维护树状数组即可,注意边界的判断。
有一个地方WA 哭我了要,就是每次修改后,我忘记了修改串上的字母。
代码示例:
#define ll long long
const int maxn = 1e5+5;

char s[maxn];
int c[12][maxn];
int lowbit(int x) {return x&(-x);}
int len;

void update(int num, int p){
    for(int i = p; i <= len; i += lowbit(i)){
        c[num][i]++;
    }       
}
 
void init(){
    for(int i = 1; i <= len; i++){
        update(s[i]-'0', i);
    }   
}
 
void update2(int num, int p){
    for(int i = p; i <= len; i += lowbit(i)){
        c[num][i]--;
    }
}
 
ll add(int x, int p){
    ll sum = 0;
    for(int i = p; i >= 1; i -= lowbit(i)){
        sum += 1ll*c[x][i];
    }
    return sum;
}
 
int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int q, l, r;
    int p, x;
     
    scanf("%s", s+1);
    len = strlen(s+1);
    init();
    cin >> q >> l >> r;
    ll ans = 0;
    
    for(int i = 1; i <= len; i++){
        for(int j = 0; j <= 9; j++){
            int b = i+r-1, a = i+l-1;
            if (a <= len && j < (s[i]-'0')) ans += 1ll*add(j, min(len, b))-1ll*add(j, a-1);
        }
    }
    
    for(int i = 1; i <= q; i++){
        scanf("%d%d", &p, &x);
        ll sum = 0;
        for(int j = 0; j <= 9; j++){
            int b = p+r-1, a = p+l-1;
            if (a <= len && j < (s[p]-'0')) sum += 1ll*add(j, min(len, b))-1ll*add(j, a-1);
            a = p-r+1, b = p-l+1;
            a = max(a, 1);
            if (b >= 1 && j > (s[p]-'0')) sum += 1ll*add(j, b)-1ll*add(j, a-1); 
        }    
        update2(s[p]-'0', p);
        update(x, p);
        ll sum2 = 0;
        for(int j = 0; j <= 9; j++){
            int b = p+r-1, a = p+l-1;
            if (a <= len && j < x) sum2 += 1ll*add(j, min(len, b))-1ll*add(j, a-1);
            a = p-r+1, b = p-l+1;
            a = max(a, 1);
            if (b >= 1 && j > x) sum2 += 1ll*add(j, b)-1ll*add(j, a-1);
        }
        ans = ans-sum+sum2;
        printf("%lld\n", ans);
        s[p] = '0'+x;
    }
    return 0;
}

 

posted @ 2018-05-12 17:20  楼主好菜啊  阅读(218)  评论(0编辑  收藏  举报