链接:https://www.nowcoder.com/acm/contest/112/D
来源:牛客网
一个只含数字的字符串,q次操作,每次操作将第i位数字改为x,每次操作后,统计长度在[l, r]之间且首数字大于尾数字的子串的个数。
第一行一个只含数字的字符串;
第二行3个整数q, l, r;
接下来q行,每行两个整数i, x。
输出q行,每行一个整数,表示长度在[l, r]之间且首数字大于尾数字的子串的个数。
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;
}
原文:https://www.cnblogs.com/ccut-ry/p/9029285.html