2018 吉林 H

題意

nn個字符串,在區間每個字符串兩端加上一個字符,並求數字和(加的數字都是單位(090\to9))。

題解

首先要知道,對於單個數。
加上ddd1010len+sum+dd*10*10^{len}+sum+d
區間就是,d10(10len1+10len2+...+10lenr)+sum+(d1+d2+...+dn)d*10*(10^{len_1}+10^{len_2}+...+10^{len_r})+sum+(d_1+d_2+...+d_n)

需要維護的信息

考慮用線段樹,需要:
1、維護區間和sumsum
2、維護左邊的10leni10^{len_i}的次方和RR
爲了維護11操作,我們還需要:
維護左邊的dd的和[lazyrlazy_r]
維護當前加了幾次(用於pushdownpushdown)[addadd]
維護右邊的和[lazydlazy_d]

對於345543345543,原串爲5555,加上4433
右邊的信息則是4545,lazyd=43lazy_d=43
左邊的信息則是3434lazyr=34lazy_r=34
增加的信息是22add=2add=2
這三個都是懶標記。

如何維護

真正難點是兩種情況:
1、同一區間加兩次:
[1,2][1,2]加兩次
左邊就是要很多位,只有已有的RR部分信息不用考慮,新加入的要考慮:
lazyr=lazyr+d10addlazy_r=lazy_r+d*10^{add}
右邊的就是普通的和:
lazyd=lazyd10+dlazy_d=lazy_d*10+d
2、不同區間但是有先後關係:
先小區間[1,2][1,2],再選上一層區間[1,4][1,4],要保證傳到[1,1][1,1]的信息正確。

傳遞lazylazy的時候也需要注意(注意原來有lazylazy的情況如何增加新的信息):
lson>lazyr=lson>lazyr+lazyr10lson>addlson->lazy_r=lson->lazy_r+lazy_r*10^{lson->add}
lson>lazyd=lson>lazyd10add+lazydlson->lazy_d=lson->lazy_d*10^{add}+lazy_d

這些都完成了之後,pushdownpushdownsumsum的更新即爲:
sum=sum10add+lazyd+lazyrR10addsum=sum*10^{add}+lazy_d+lazy_r*R*10^{add}

總結

我死在了左邊信息不考慮右邊位數那一步,我一開始了考慮了右邊位數,但是這樣很難維護傳遞lazylazy的部分,這樣寫不僅好寫還不容易錯。

#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);
            }
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章