Wannafly挑战赛15 D-数字串(线段树)

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

题目描述

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

输入描述:

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

输出描述:

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

题解:
更改i位置的数为x,查询left~i大于x的数有多少个,
查询i~right小于x的数有几个。
注意左右边界的确定问题,防止越界。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+7;
char t[maxn];
int a[maxn];
struct node
{
    int left,right,mid;
    int x[12];
}tree[maxn<<2];
void push_up(int rt)
{
    for(int i=0;i<=9;i++)
        tree[rt].x[i]=tree[rt<<1].x[i]+tree[rt<<1|1].x[i];
}
void build(int l,int r,int rt)
{
    tree[rt].left=l;
    tree[rt].right=r;
    tree[rt].mid=(l+r)>>1;
    if(l==r)
    {
        for(int i=9;i>=0;i--)
        {
            if(i==a[l])
                tree[rt].x[i]=1;
            else
                tree[rt].x[i]=0;
        }
        return;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    push_up(rt);
}
int query(int l,int r,int rt,int k)
{
    if(tree[rt].left>=l&&tree[rt].right<=r)
    {
        ll ans=0;
        for(int i=9;i>k;i--)
            ans+=tree[rt].x[i];
        return ans;
    }
    ll s=0;
    if(l<=tree[rt].mid)
        s+=query(l,r,rt<<1,k);
    if(r>tree[rt].mid)
        s+=query(l,r,rt<<1|1,k);
    return s;
}
void update(int L,int rt,int k)
{
    if(tree[rt].left==tree[rt].right)
    {
       for(int i=9;i>=0;i--)
       {
           if(i==k)
            tree[rt].x[i]=1;
           else
            tree[rt].x[i]=0;
       }
        return;
    }
    if(L<=tree[rt].mid)
        update(L,rt<<1,k);
    else
        update(L,rt<<1|1,k);
    push_up(rt);
}
int main()
{
    scanf("%s",t+1);
    int len=strlen(t+1);
    int l,r;
    int Q;scanf("%d",&Q);
    scanf("%d%d",&l,&r);
    for(int i=1;i<=len;i++)
        a[i]=t[i]-'0';
    build(1,len,1);
    ll ans=0;
    for(int i=1;i<=len;i++)
    {
        int L1=max(1,i-r+1),R1=max(1,i-l+1);
        ll x1=0,x2=0,x3=0;
        if(i-R1+1<l)R1=i+1-l;
        if(i-L1+1>r)L1=i+1-r;
        if(i!=1)x1=query(L1,R1,1,a[i]);
        L1=min(len,i+l-1);R1=min(len,i+r-1);
        if(R1-i+1>r)R1=r+i-1;
        if(L1-i+1<l)L1=l+i-1;
        if(i!=len)
        {
            x2=query(L1,R1,1,-1);
            x3=query(L1,R1,1,a[i]-1);
        }
        ans=ans+x1+x2-x3;
    }
    ans/=2;
    while(Q--)
    {
        int i,x;
        scanf("%d%d",&i,&x);
        ll ans1,ans2;
        int L1=max(1,i-r+1),R1=max(1,i-l+1);
        ll x1=0,x2=0,x3=0;
        if(i-R1+1<l)R1=i+1-l;
        if(i-L1+1>r)L1=i+1-r;
        if(i!=1)x1=query(L1,R1,1,a[i]);
        L1=min(len,i+l-1);R1=min(len,i+r-1);
        if(R1-i+1>r)R1=r+i-1;
        if(L1-i+1<l)L1=l+i-1;
        if(i!=len)
        {
            x2=query(L1,R1,1,-1);
            x3=query(L1,R1,1,a[i]-1);
        }
        a[i]=x;
        ans1=x1+x2-x3;
        update(i,1,x);
        L1=max(1,i-r+1),R1=max(1,i-l+1);
        x1=0,x2=0,x3=0;
        if(i-R1+1<l)R1=i+1-l;
        if(i-L1+1>r)L1=i+1-r;
        if(i!=1)x1=query(L1,R1,1,x);
        L1=min(len,i+l-1);R1=min(len,i+r-1);
        if(R1-i+1>r)R1=r+i-1;
        if(L1-i+1<l)L1=l+i-1;
        if(i!=len)
        {
            x2=query(L1,R1,1,-1);
            x3=query(L1,R1,1,x-1);
        }
        ans2=x1+x2-x3;
        ans=ans+ans2-ans1;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/albertluf/article/details/80290385