建立多个树状数组
链接: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; }
东北日出西边雨 道是无情却有情