一个只含数字的字符串,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;
题解:
相当于求间隔距离在[l, r]之间的逆序对数。
因为所有数在[0,9]之间,所以可用 10 个树状数组维护数字每种的前缀和。
初始化求第一遍 ans 的时候,对于每个数考虑前面与该点的距离在[l,r]之间的所有点。
每次修改,减去当前位置的数对答案的影响,再加上更新后的数对答案的影响。
考虑前面和后面与该点的距离在[l,r]之间的所有点,更新 ans 即可。
时间复杂度:n*logn
树状数组
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
char str[maxn];
int l,r,len;
struct BIT
{
int c[10][maxn];
int lowbit(int x) {return x & -x;}
void init()
{
memset(c,0,sizeof(c));
}
void update(int x,int pos,int val)
{
for(int i=pos;i0;i-=lowbit(i)) ans += c[x][i];
return ans;
}
}bit;
int ask_left(int x,int pos) /// 统计在[pos-r+1,pos-l+1] 中有多少大于x的
{
int ans = 0;
for(int i=x+1;i<10;i++) ans += bit.query(i,max(pos-l+1,0)) - bit.query(i,max(pos-r,0));
return ans;
}
int ask_right(int x,int pos,int len) /// 统计在[pos+l-1,pos+r-1] 中有多少个小于x的
{
int ans = 0;
for(int i=x-1;~i;i--) ans += bit.query(i,min(pos+r-1,len)) - bit.query(i,min(pos+l-2,len));
return ans;
}
int main()
{
while(~scanf("%s",str+1))
{
bit.init();
int q;
scanf("%d%d%d",&q,&l,&r);
int len = strlen(str+1);
ll ans = 0;
for(int i=1;i<=len;i++) { /// 得出未修改前的总逆序对个数
int x = str[i]-'0';
bit.update(x,i,1);
ans += ask_left(x,i);
}
// printf("%d\n",ans);
int pos,x;
while(q--)
{
scanf("%d%d",&pos,&x);
int y = str[pos] - '0';
ans -= ask_left(y,pos) + ask_right(y,pos,len); /// 删除当前位置对答案的影响
bit.update(y,pos,-1);
str[pos] = x + '0';
bit.update(x,pos,1);
ans += ask_left(x,pos) + ask_right(x,pos,len); /// 增加当前位置对答案的影响
printf("%lld\n",ans);
}
}
return 0;
}
线段树
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll arr[maxn];
char str[maxn];
int l,r,len;
struct SegTree
{
ll sum[maxn<<2];
void init()
{
memset(sum,0,sizeof(sum));
}
void push_up(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void build(ll arr[],int l,int r,int rt)
{
if(l == r) {
sum[rt] = arr[l];
return ;
}
int mid = (l + r) >> 1;
build(arr,l,mid,rt<<1);
build(arr,mid+1,r,rt<<1|1);
push_up(rt);
}
void activate(int pos,ll val,int l,int r,int rt)
{
if(l == r) {
sum[rt] = val;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) activate(pos,val,l,mid,rt<<1);
else activate(pos,val,mid+1,r,rt<<1|1);
push_up(rt);
}
void update(int pos,ll val,int l,int r,int rt)
{
if(l == r)
{
sum[rt] += val;
return ;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(pos,val,l,mid,rt<<1);
else update(pos,val,mid+1,r,rt<<1|1);
push_up(rt);
}
ll query(int ql,int qr,int l,int r,int rt)
{
if(ql == l && qr == r) return sum[rt];
int mid = (l + r) >> 1;
if(qr <= mid) return query(ql,qr,l,mid,rt<<1);
if(ql > mid) return query(ql,qr,mid+1,r,rt<<1|1);
return query(ql,mid,l,mid,rt<<1) + query(mid+1,qr,mid+1,r,rt<<1|1);
}
}seg[10];
ll ask_left(int num,int pos)
{
ll res = 0,temp;
for(int i=num+1;i<10;i++) {
if(pos-l+1 <= 0) temp = 0;
else {
if(pos-r+1 <= 0) temp = seg[i].query(1,pos-l+1,1,len,1);
else temp = seg[i].query(pos-r+1, pos-l+1,1,len,1);
}
res += temp;
}
return res;
}
ll ask_right(int num,int pos)
{
ll res = 0,temp;
for(int i=num-1;i>=0;i--) {
if(pos+l-1>len) temp = 0;
else {
if(pos+r-1 > len) temp = seg[i].query(pos+l-1,len,1,len,1);
else temp = seg[i].query(pos+l-1,pos+r-1,1,len,1);
}
res += temp;
}
return res;
}
int main()
{
while(~scanf("%s",str))
{
int q;
scanf("%d%d%d",&q,&l,&r);
for(int i=0;i<10;i++) seg[i].init();
len = strlen(str);
for(int i=1;i<=len;i++) arr[i] = str[i-1]^'0';
ll ans = 0;
for(int i=1;i<=len;i++) {
seg[arr[i]].update(i,1,1,len,1);
ans += ask_left(arr[i],i);
}
//printf("%lld\n",ans);
int pos,x;
while(q--)
{
scanf("%d%d",&pos,&x);
int y = arr[pos];
ans -= ask_left(y,pos) + ask_right(y,pos);
arr[pos] = x;
seg[y].update(pos,-1,1,len,1);
seg[x].update(pos,1,1,len,1);
ans += ask_left(x,pos) + ask_right(x,pos);
printf("%lld\n",ans);
}
}
return 0;
}