2018 吉林 H

题意

n n n个字符串,在区间每个字符串两端加上一个字符,并求数字和(加的数字都是单位( 0 → 9 0\to9 09))。

题解

首先要知道,对于单个数。
加上 d d d d ∗ 10 ∗ 1 0 l e n + s u m + d d*10*10^{len}+sum+d d1010len+sum+d
区间就是, d ∗ 10 ∗ ( 1 0 l e n 1 + 1 0 l e n 2 + . . . + 1 0 l e n r ) + s u m + ( d 1 + d 2 + . . . + d n ) d*10*(10^{len_1}+10^{len_2}+...+10^{len_r})+sum+(d_1+d_2+...+d_n) d10(10len1+10len2+...+10lenr)+sum+(d1+d2+...+dn)

需要维护的信息

考虑用线段树,需要:
1、维护区间和 s u m sum sum
2、维护左边的 1 0 l e n i 10^{len_i} 10leni的次方和 R R R
为了维护 1 1 1操作,我们还需要:
维护左边的 d d d的和[ l a z y r lazy_r lazyr]
维护当前加了几次(用于 p u s h d o w n pushdown pushdown)[ a d d add add]
维护右边的和[ l a z y d lazy_d lazyd]

对于 345543 345543 345543,原串为 55 55 55,加上 4 4 4 3 3 3
右边的信息则是 45 45 45, l a z y d = 43 lazy_d=43 lazyd=43
左边的信息则是 34 34 34 l a z y r = 34 lazy_r=34 lazyr=34
增加的信息是 2 2 2 a d d = 2 add=2 add=2
这三个都是懒标记。

如何维护

真正难点是两种情况:
1、同一区间加两次:
[ 1 , 2 ] [1,2] [1,2]加两次
左边就是要很多位,只有已有的 R R R部分信息不用考虑,新加入的要考虑:
l a z y r = l a z y r + d ∗ 1 0 a d d lazy_r=lazy_r+d*10^{add} lazyr=lazyr+d10add
右边的就是普通的和:
l a z y d = l a z y d ∗ 10 + d lazy_d=lazy_d*10+d lazyd=lazyd10+d
2、不同区间但是有先后关系:
先小区间 [ 1 , 2 ] [1,2] [1,2],再选上一层区间 [ 1 , 4 ] [1,4] [1,4],要保证传到 [ 1 , 1 ] [1,1] [1,1]的信息正确。

传递 l a z y lazy lazy的时候也需要注意(注意原来有 l a z y lazy lazy的情况如何增加新的信息):
l s o n − > l a z y r = l s o n − > l a z y r + l a z y r ∗ 1 0 l s o n − > a d d lson->lazy_r=lson->lazy_r+lazy_r*10^{lson->add} lson>lazyr=lson>lazyr+lazyr10lson>add
l s o n − > l a z y d = l s o n − > l a z y d ∗ 1 0 a d d + l a z y d lson->lazy_d=lson->lazy_d*10^{add}+lazy_d lson>lazyd=lson>lazyd10add+lazyd

这些都完成了之后, p u s h d o w n pushdown pushdown s u m sum sum的更新即为:
s u m = s u m ∗ 1 0 a d d + l a z y d + l a z y r ∗ R ∗ 1 0 a d d sum=sum*10^{add}+lazy_d+lazy_r*R*10^{add} sum=sum10add+lazyd+lazyrR10add

总结

我死在了左边信息不考虑右边位数那一步,我一开始了考虑了右边位数,但是这样很难维护传递 l a z y lazy lazy的部分,这样写不仅好写还不容易错。

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn = 5e5+510;
const int mod = 1e9+7;

struct tree2{
    tree2 *lson,*rson;
    ll sum,mr;
    ll add,lazy_r,lazy_d;
}dizhi[maxn<<2],*root=&dizhi[0];

int n,m,t=1;
ll A[maxn];

void push_up(tree2 *tree,int l,int r){
    tree->sum=(tree->lson->sum+tree->rson->sum)%mod;
    tree->mr=(tree->lson->mr+tree->rson->mr)%mod;
}

void push_down(tree2 *tree,int l,int r){
    if(!tree->add)return ;
    int mid=(l+r)>>1;
    tree->lson->sum=(tree->lson->sum*A[tree->add])%mod;
    tree->lson->sum=(tree->lson->sum+tree->lson->mr%mod*tree->lazy_r%mod*A[tree->add])%mod;
    tree->lson->sum=(tree->lson->sum+1ll*(mid-l+1)*tree->lazy_d%mod)%mod;
    tree->rson->sum=(tree->rson->sum*A[tree->add])%mod;
    tree->rson->sum=(tree->rson->sum+tree->rson->mr%mod*tree->lazy_r%mod*A[tree->add])%mod;
    tree->rson->sum=(tree->rson->sum+1ll*(r-mid)*tree->lazy_d%mod)%mod;//对sum

    tree->lson->mr=tree->lson->mr*A[tree->add]%mod*A[tree->add]%mod;
    tree->rson->mr=tree->rson->mr*A[tree->add]%mod*A[tree->add]%mod;

    tree->lson->lazy_d=(tree->lson->lazy_d*A[tree->add]%mod+tree->lazy_d)%mod;
    tree->rson->lazy_d=(tree->rson->lazy_d*A[tree->add]%mod+tree->lazy_d)%mod;
    tree->lson->lazy_r=(tree->lson->lazy_r+tree->lazy_r*A[tree->lson->add]%mod)%mod;
    tree->rson->lazy_r=(tree->rson->lazy_r+tree->lazy_r*A[tree->rson->add]%mod)%mod;;
    tree->lson->add=(tree->add+tree->lson->add)%mod;
    tree->rson->add=(tree->add+tree->rson->add)%mod;

    tree->add=tree->lazy_d=tree->lazy_r=0;
}

void build(tree2 *tree,int l,int r){
    tree->add=tree->lazy_d=tree->lazy_r=0;
    if(l==r){
        tree->sum=0;
        tree->mr=1;
        return ;
    }
    tree->lson=&dizhi[t++];
    tree->rson=&dizhi[t++];
    int mid=(l+r)>>1;
    build(tree->lson,l,mid);
    build(tree->rson,mid+1,r);
    push_up(tree,l,r);
}

void update(tree2 *tree,int l,int r,int x,int y,int d){
    if(x<=l&&r<=y){
        tree->sum=(tree->sum*10%mod+1ll*(r-l+1)*d%mod+d*tree->mr%mod*10)%mod;
        tree->lazy_d=(tree->lazy_d*10%mod+d)%mod;
        tree->lazy_r=(tree->lazy_r+1ll*d*A[tree->add]%mod)%mod;
        tree->mr=tree->mr*100%mod;
        tree->add++;
      //  cout<<tree->sum<<" "<<tree->mr<<" "<<tree->lazy_d<<" "<<tree->lazy_r<<endl;
        return ;
    }
    push_down(tree,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)update(tree->lson,l,mid,x,y,d);
    if(y>mid)update(tree->rson,mid+1,r,x,y,d);
    push_up(tree,l,r);
}

int query(tree2 *tree,int l,int r,int x,int y){
    if(x<=l&&r<=y)return tree->sum;
    push_down(tree,l,r);
    int mid=(l+r)>>1;
    int t1=0,t2=0;
    if(x<=mid)t1=query(tree->lson,l,mid,x,y);
    if(y>mid)t2=query(tree->rson,mid+1,r,x,y);
    return (t1+t2)%mod;
}

int main(){
    int T,kase=0;cin>>T;
    A[0]=1;
    for(int i=1;i<maxn;i++)A[i]=10*A[i-1]%mod;
    while(T--){
        t=1;
        scanf("%d%d",&n,&m);
        printf("Case %d:\n",++kase);
        build(root,1,n);
        for(int i=1;i<=m;i++){
            char str[8];scanf("%s",str);
            int l,r,d;
            if(str[0]=='w'){
                scanf("%d%d%d",&l,&r,&d);
                update(root,1,n,l,r,d);
            }
            else{
                scanf("%d%d",&l,&r);
                ll ans=query(root,1,n,l,r);
                printf("%lld\n",ans);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值