hdoj6562 Lovers(线段树)
传送:http://acm.hdu.edu.cn/showproblem.php?pid=6562
题意:有$n$个字符串,初始为空。$m$次操作,每次操作如下:
1. $wrap l,r,d$ 代表给区间$[l,r]$内的每个字符串前后都加上数字$d$,即串变为$ds_id$;
2. $query l,r$ 代表询问区间$[l,r]$内的和。
数据范围:
$1 \le T \le 5, 1 \le n, m \le 1e5, 1 \le l \le r \le n.$
分析:
求区间和。(感觉是线段树,然后和学妹开始了漫漫路。可是没有树出来qaq
线段树每个结点维护:区间和$sum$,前缀的增量$lazy1$,后缀的增量$lazy2$,更新的长度$lazylen$,以及区间数值的长度$len$。
但是这里的更新长度和区间数值长度存储是表示为$10^k$,因为每次算贡献的时候这样方便计算,避免多次调用$pow$函数。
//开始考虑每增加一个$x$对于区间的影响:假设对于区间$[l,r]$增加了$x$。
对于前缀$lazy1$的影响:$lazy1=原有的更新长度lazylen*x+lazy1$
对于后缀$lazy2$的影响:$lazy2=lazy2*10+x$
对于区间和$sum$的影响:$sum=x*tree[root].len*10+(tree[root].r-tree[root].l+1)*x+tree[root].sum*10)$
对于区间更新长度$lazylen$:$lazylen*=10$
对于区间数值长度$len$:$len*=100$
然后每次需要把更新下传给左右儿子,然后取消他本身的更新标记。
每次$update$都需要$pushdown$和$pushup$。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=2e5+10; 5 const int mod=1e9+7; 6 struct node{ 7 ll l,r,sum; 8 ll lazylen,lazy1,lazy2,len; 9 }tree[maxn<<2]; 10 ll ans; 11 void pushup(int root){ 12 tree[root].len=(tree[root<<1].len+tree[root<<1|1].len)%mod; 13 tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%mod; 14 } 15 void build(int root,int l,int r){ 16 tree[root].l=l; tree[root].r=r;tree[root].sum=0; 17 tree[root].lazylen=1; tree[root].lazy1=0;tree[root].lazy2=0;tree[root].len=0; 18 if (l==r){ 19 tree[root].len=1; 20 return ; 21 } 22 int mid=(l+r)>>1; 23 build(root<<1,l,mid); 24 build(root<<1|1,mid+1,r); 25 pushup(root); 26 } 27 void pushdown(int root){ 28 if (tree[root].lazylen>1){ 29 tree[root<<1].lazy1=(tree[root<<1].lazylen*tree[root].lazy1+tree[root<<1].lazy1)%mod; 30 tree[root<<1].lazy2=(tree[root<<1].lazy2*tree[root].lazylen+tree[root].lazy2)%mod; 31 tree[root<<1|1].lazy1=(tree[root<<1|1].lazylen*tree[root].lazy1+tree[root<<1|1].lazy1)%mod; 32 tree[root<<1|1].lazy2=(tree[root<<1|1].lazy2*tree[root].lazylen+tree[root].lazy2)%mod; 33 34 tree[root<<1].sum=(tree[root].lazy1*tree[root<<1].len%mod*tree[root].lazylen%mod 35 +(tree[root<<1].r-tree[root<<1].l+1)*tree[root].lazy2%mod+tree[root<<1].sum*tree[root].lazylen)%mod; 36 tree[root<<1|1].sum=(tree[root].lazy1*tree[root<<1|1].len%mod*tree[root].lazylen%mod 37 +(tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].lazy2%mod+tree[root<<1|1].sum*tree[root].lazylen)%mod; 38 39 tree[root<<1].len=(tree[root<<1].len*tree[root].lazylen%mod*tree[root].lazylen)%mod; 40 tree[root<<1|1].len=(tree[root<<1|1].len*tree[root].lazylen%mod*tree[root].lazylen)%mod; 41 42 tree[root<<1].lazylen=(tree[root<<1].lazylen*tree[root].lazylen)%mod; 43 tree[root<<1|1].lazylen=(tree[root<<1|1].lazylen*tree[root].lazylen)%mod; 44 45 tree[root].lazy1=0;tree[root].lazy2=0;tree[root].lazylen=1; 46 } 47 } 48 49 void update(int root,int l,int r,int x){ 50 if (tree[root].l>=l && tree[root].r<=r){ 51 tree[root].sum=(x*tree[root].len*10%mod+(tree[root].r-tree[root].l+1)*x%mod+tree[root].sum*10)%mod; 52 tree[root].len=(tree[root].len*100)%mod; 53 54 tree[root].lazy1=(tree[root].lazylen*x+tree[root].lazy1)%mod; 55 tree[root].lazy2=(tree[root].lazy2*10+x)%mod; 56 tree[root].lazylen=tree[root].lazylen*10%mod; 57 pushdown(root); 58 return ; 59 } 60 pushdown(root); 61 int mid=(tree[root].l+tree[root].r)>>1; 62 if (mid>=l) update(root<<1,l,r,x); 63 if (mid<r) update(root<<1|1,l,r,x); 64 pushup(root); 65 } 66 void query(int root,int l,int r){ 67 if (tree[root].l>=l && tree[root].r<=r){ 68 (ans+=tree[root].sum)%=mod; 69 return ; 70 } 71 pushdown(root); 72 int mid=(tree[root].l+tree[root].r)>>1; 73 if (mid>=l) query(root<<1,l,r); 74 if (mid<r) query(root<<1|1,l,r); 75 } 76 int main(){ 77 int t,n,m,x,y,z,_=0; scanf("%d",&t); 78 string s; 79 while (t--){ 80 scanf("%d%d",&n,&m); 81 build(1,1,n); 82 printf("Case %d:\n",++_); 83 while (m--){ 84 cin >> s; 85 if (s=="wrap"){ 86 scanf("%d%d%d",&x,&y,&z); 87 update(1,x,y,z); 88 } 89 else{ 90 scanf("%d%d",&x,&y); 91 ans=0; 92 query(1,x,y); 93 printf("%lld\n",ans); 94 } 95 } 96 } 97 return 0; 98 }