题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6562
题目大意:有n个空串,两种操作,第一种操作是让l到r区间内的串开头结尾加上d,比如之前是33,d是5,那就变成5335,另一个操作是l到r区间内的所有串求和并输出
题目思路:讲道理,直接自闭,太难打了。。线段树需要维护五个变量,分别是表示的区间的和sum,表示的区间的数字长度len的len,表示区间右边应该加上的数字的延迟标记为lazr,左边应该加上的数字的延迟标记为lazl,设这些数字的长度的长度为,那么lazylen就是
查询是最好写的,直接按照普通的线段树加sum就完事了
更新的时候,首先更新sum,因为原先的数字需要乘上10为新添的数字留个空位,所以第一项就是sum*10,然后由于这一区间内所有数字都加上了val,也就是第二项需要是(r-l+1)*val,第三项就是在最左边加上val,由于之前维护的len是,所以我们只需要在len的基础上*10就是各个区间内的数字要放数字的位置。比如之前是33的话,val是5,之前的len是10^2=100,乘上10就是千位的位置,正好与我们想要的位置符合。
然后更新len,因为多出来俩数字,也就是多了俩0,乘个100即可
接着更新lazr,之前的lazr*10给新人空位置,然后+val即可
lazl的话是往原来数字的左边加,由于lazlen已经记录了当前应该往哪个位加,直接lazl+val*lazlen就完事
lazlen是每次多一个数字,所以乘个10即可
接着讲最最最难的延迟标记下传,更新孩子的sum的时候,先让孩子的sum乘以父亲的lazlen,使得孩子的sum右边留下空间放父亲的lazr,然后加上孩子的(r-l+1)*父亲的lazr,左边加就是父亲的lazl*孩子的len再乘上父亲的lazlen。
孩子的len就是本身乘两次父亲的lazlen,因为lazlen是lazr和lazl各自的长度,所以总长是这俩共同贡献,需要乘两次
lazl就是父亲的lazl跟到孩子的lazl后面,也就是父亲的lazl*孩子的lazlen+孩子之前的lazl
lazr就是孩子后面空出父亲的lazlen的距离,给父亲的lazr留位置,也就是孩子的lazr*父亲的lazlen+孩子之前的lazr
lazlen就是孩子的lazlen乘上父亲的lazlen,因为它是单单一边的长度,所以只用一遍
以下是代码:
#include<iostream>
using namespace std;
#define ll long long
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MOD = 1e9+7;
const ll MAXN = 1e5+5;
char s[10];
struct node{
ll l,r,sum,len,lazl,lazr,lazlen;
}a[MAXN<<2];
void build(ll rt,ll l,ll r){
a[rt].l=l,a[rt].r=r;
a[rt].sum=a[rt].lazl=a[rt].lazr=0;
a[rt].lazlen=1;
if(l==r){
a[rt].len=1;
return;
}
ll mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
a[rt].len=(a[rt<<1].len+a[rt<<1|1].len)%MOD;
}
void spread(ll rt){
if(a[rt].lazlen>1){
a[rt<<1].sum=((ll)a[rt].lazlen*a[rt<<1].sum%MOD+(ll)a[rt].lazr*(a[rt<<1].r-a[rt<<1].l+1)%MOD+(ll)a[rt].lazl*a[rt<<1].len%MOD*a[rt].lazlen%MOD)%MOD;
a[rt<<1|1].sum=((ll)a[rt].lazlen*a[rt<<1|1].sum%MOD+(ll)a[rt].lazr*(a[rt<<1|1].r-a[rt<<1|1].l+1)%MOD+(ll)a[rt].lazl*a[rt<<1|1].len%MOD*a[rt].lazlen%MOD)%MOD;
a[rt<<1].len=(ll)a[rt<<1].len*a[rt].lazlen%MOD*a[rt].lazlen%MOD;
a[rt<<1|1].len=(ll)a[rt<<1|1].len*a[rt].lazlen%MOD*a[rt].lazlen%MOD;
a[rt<<1].lazl=((ll)a[rt].lazl*a[rt<<1].lazlen%MOD+a[rt<<1].lazl)%MOD;
a[rt<<1|1].lazl=((ll)a[rt].lazl*a[rt<<1|1].lazlen%MOD+a[rt<<1|1].lazl)%MOD;
a[rt<<1].lazr=((ll)a[rt<<1].lazr*a[rt].lazlen%MOD+a[rt].lazr)%MOD;
a[rt<<1|1].lazr=((ll)a[rt<<1|1].lazr*a[rt].lazlen%MOD+a[rt].lazr)%MOD;
a[rt<<1].lazlen=((ll)a[rt<<1].lazlen*a[rt].lazlen)%MOD;
a[rt<<1|1].lazlen=((ll)a[rt<<1|1].lazlen*a[rt].lazlen)%MOD;
a[rt].lazl=a[rt].lazr=0;
a[rt].lazlen=1;
}
}
void update(ll rt,ll l,ll r,ll val){
if(a[rt].l>=l&&a[rt].r<=r){
a[rt].sum=((a[rt].r-a[rt].l+1)*val%MOD+a[rt].sum*10ll%MOD+a[rt].len*val*10ll%MOD)%MOD;
a[rt].len=a[rt].len*100ll%MOD;
a[rt].lazr=(a[rt].lazr*10ll+val)%MOD;
a[rt].lazl=(a[rt].lazl+a[rt].lazlen*(ll)val)%MOD;
a[rt].lazlen=a[rt].lazlen*10ll%MOD;
return;
}
spread(rt);
ll mid=(a[rt].l+a[rt].r)>>1;
if(l<=mid)update(rt<<1,l,r,val);
if(r>mid)update(rt<<1|1,l,r,val);
a[rt].sum=(a[rt<<1].sum+a[rt<<1|1].sum)%MOD;
a[rt].len=(a[rt<<1].len+a[rt<<1|1].len)%MOD;
}
ll query(ll rt,ll l,ll r){
if(a[rt].l>=l&&a[rt].r<=r){
return a[rt].sum;
}
spread(rt);
ll mid=(a[rt].l+a[rt].r)>>1;
ll ans=0;
if(l<=mid)ans=(ans+query(rt<<1,l,r))%MOD;
if(r>mid)ans=(ans+query(rt<<1|1,l,r))%MOD;
return ans;
}
int main()
{
ll t,n,m,l,r,d;
scanf("%lld",&t);
rep(_,1,t){
printf("Case %lld:\n",_);
scanf("%lld%lld",&n,&m);
build(1,1,n);
while(m--){
scanf("%s",s);
if(s[0]=='w'){
scanf("%lld%lld%lld",&l,&r,&d);
update(1,l,r,d);
}
else{
scanf("%lld%lld",&l,&r);
ll ans=query(1,l,r);
printf("%lld\n",ans);
}
}
}
return 0;
}