[hdu6562][CCPC2018吉林站]Lovers

这是一篇关于利用线段树解决编程竞赛问题HDU6562 Lovers的博客。题目涉及字符串操作,包括在指定区间内向字符串前后添加数字以及计算字符串转化为数字后的区间和。解题策略是构建线段树,维护每个节点的字符串长度、数值总和以及懒惰标记,以高效处理区间更新和查询操作。
摘要由CSDN通过智能技术生成

Problem Description
The Fool comes to a cross-road, filled with energy, confidence and purpose, knowing exactly where he wants to go and what he wants to do. But he comes to a dead stop. A flowering tree marks the path he wants to take, the one he’s been planning on taking. But standing before a fruit tree marking the other path is a woman. The Fool has met and had relationships with women before, some far more beautiful and alluring. But she is different. Seeing her, he feels as though he’s just been shot in the heart with cupid’s arrow.

There are n n n empty strings:
s 1 , s 2 , . . . , s n s_1, s_2, . . . , s_n s1,s2,...,sn.

You are required to perform two kinds of operations:
wrap l r d: change s i s_i si to d s i d ds_id dsid for all l ≤ i ≤ r l ≤ i ≤ r lir, where d d d is a digit character.
query l r : query ∑ i = l r v a l u e ( s i ) ( m o d 1 0 9 + 7 ) \sum_{i=l}^r value(s_i) (mod 10^9 + 7) i=lrvalue(si)(mod109+7), where value(s) is the number that string s s s represents.
Note that the value of an empty string is 0 0 0.

Input
The first line contains one integer T, which denote the number of cases.
For each case, the first line contains two integer n and m where n n n is the number of strings and m m m is the number of operations.
Each line of the following m lines contains an operation with format :

wrap l r d

or

query l r

Output
For each case, you should output "Case i:"in a line, where i is the case number starting from 1.
Then for each query operation in that case, output a line that contains a single integer that representing the answer for that query operation.

Sample Input

2
3 2
wrap 1 3 1
query 1 2
4 4
wrap 1 3 0
wrap 2 4 3
query 1 4
query 2 3

Sample Output

Case 1:
22
Case 2:
6039
6006

Hint

1 ≤ T ≤ 5, 1 ≤ n, m ≤ 1e5, 1 ≤ l ≤ r ≤ n.

题意:
给定一个长度为 n ( n &lt; = 1 0 5 ) n(n&lt;=10^5) nn<=105,初始全是空串的字符串序列s,有两种操作,第一个操作是给区间里面所有的字符串的头尾加上一个数字d(0~9),第二个操作时询问一个区间里面所有字符串转为数字之后的区间和,对 1 0 9 + 7 10^9+7 109+7取模。

题解:
线段树
记录以下值:
len: ∑ i = l r 1 0 l e n g t h ( s i ) + 1 \sum_{i=l}^r 10^{length(s_i)+1} i=lr10length(si)+1
w: ∑ i = l r s i \sum_{i=l}^r s_i i=lrsi
taglen:len的lazy标记
tagl:在这个区间中,左边位置放数字的lazy标记
tagr:在这个区间中,右边位置放置数字的lazy标记

我们知道,对于一个区间来说,在所有字符串左右增加d的操作是修改w
w = w ∗ 10 + d ∗ ( r − l + 1 ) + d ∗ l e n w = w*10+d*(r-l+1)+d*len w=w10+d(rl+1)+dlen
下传标记的时候要注意以下情况
tagl 为变为 t a g l + l e n ∗ L tagl + len*L tagl+lenL (L为父节点的tagl)
tagr 为变为 t a g r ∗ L + R tagr*L + R tagrL+R (R为父节点的tagr)
w = R ∗ ( r − l + 1 ) + w ∗ t l + L ∗ t l ∗ l e n / 10 w = R*(r-l+1)+w*tl+L*tl*len/10 w=R(rl+1)+wtl+Ltllen/10(tl为父节点的taglen) 要记得除以10

#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007LL
using namespace std;
int n,m;
ll ovc;
ll tin(ll y){
    if(y==0)return 1;
    ll temp=tin(y>>1);
    if(y&1){
        return (((temp*temp)%MOD)*10LL)%MOD;
    }
    else return (temp*temp)%MOD;
}
struct seg{
    int l,r;
    ll len,w,tagl,tagr,taglen;
}tr[400004];
void update(int k){
    tr[k].w=(tr[k<<1].w+tr[k<<1|1].w)%MOD;
    tr[k].len=(tr[k<<1].len+tr[k<<1|1].len)%MOD;
}
void build(int k,int l,int r){
    tr[k].l=l;tr[k].r=r;
    tr[k].tagl=0;tr[k].tagr=0;tr[k].w=0;tr[k].taglen=1;
    if(l==r){
        tr[k].len=10;
        return ;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    update(k);
}

void fut(int k,ll L,ll R,ll tl){
    int l=tr[k].l,r=tr[k].r;
    tr[k].tagl+=(L*tr[k].taglen)%MOD;
    tr[k].tagl%=MOD;
    tr[k].tagr*=tl;
    tr[k].tagr%=MOD;
    tr[k].tagr=(tr[k].tagr+R)%MOD;
    tr[k].taglen=(tr[k].taglen*tl)%MOD;
    tr[k].w=((R*(r-l+1))%MOD+(tr[k].w*tl)%MOD+(((((L*tl)%MOD)*tr[k].len)%MOD)*ovc)%MOD)%MOD;
    tr[k].len=(((tr[k].len*tl)%MOD)*tl)%MOD;
}

void pushdown(int k){
    ll tl=tr[k].taglen,L=tr[k].tagl,R=tr[k].tagr;
    if(tr[k].taglen<=1)return ;
    tr[k].taglen=1;
    tr[k].tagl=0;
    tr[k].tagr=0;
    fut(k<<1,L,R,tl);
    fut(k<<1|1,L,R,tl);
}

void wrap(int k,int a,int b,ll d){
    int l=tr[k].l,r=tr[k].r;
    if(a==l&&b==r){
        ll al=(d*(r-l+1))%MOD;
        ll ar=(d*tr[k].len)%MOD;
        tr[k].w=(tr[k].w*10LL)%MOD;
        tr[k].w=(tr[k].w+((al+ar)%MOD))%MOD;
        tr[k].len=(tr[k].len*100LL)%MOD;
        tr[k].tagl+=(d*tr[k].taglen)%MOD;
        tr[k].tagl%=MOD;
        tr[k].tagr=(tr[k].tagr*10LL)%MOD;
        tr[k].tagr=(tr[k].tagr+d)%MOD;
        tr[k].taglen*=10LL;
        tr[k].taglen%=MOD;
        return ;
    }
    pushdown(k);
    int mid=(l+r)>>1;
    if(b<=mid)wrap(k<<1,a,b,d);
    else if(a>mid)wrap(k<<1|1,a,b,d);
    else{
        wrap(k<<1,a,mid,d);
        wrap(k<<1|1,mid+1,b,d);
    }
    update(k);
}
ll query(int k,int a,int b){
    int l=tr[k].l,r=tr[k].r;
    if(l==a&&r==b)return tr[k].w;
    pushdown(k);
    int mid=(l+r)>>1;
    if(b<=mid)return query(k<<1,a,b)%MOD;
    else if(a>mid)return query(k<<1|1,a,b)%MOD;
    else {
        return (query(k<<1,a,mid)+query(k<<1|1,mid+1,b))%MOD;
    }
}
void w33ha(int CASE){
    scanf("%d%d",&n,&m);
    printf("Case %d:\n",CASE);
    build(1,1,n);
    while(m--){
        char s[14];
        scanf("%s",s+1);
        int l,r;
        ll d;
        if(s[1]=='w'){
            scanf("%d%d%lld",&l,&r,&d);
            wrap(1,l,r,d);

        }
        if(s[1]=='q'){
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(1,l,r));
        }//cout<<"ppp---|"<<tr[4].w<<endl;
    }
}
int main(){
    int T;scanf("%d",&T);
    ovc=tin(MOD-2);
    for(int i=1;i<=T;i++)w33ha(i);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值