Hdu 6562-Lovers(线段树+2018CCPC吉林站)
1.题目链接
2.题意
T组样例
每组样例中,初始有n个空串,m个操作
有两种操作
(1) wrap L R X
对区间 [ L,R ] 中的每一个串的首位加上字符X,X确保为单个数字字符。
(2)query L R
查询区间 [ L,R ] 每个串所代表的数字的和
(每个串都是由数字组成的,这些数字组成的每一个串就是一个数字,区间求和)
还没有搞透这道题目的核心,只是知道是个线段树比较模板的题目,过题也是手动复制某篇博客大佬的代码过的,以下贴出手动复制代码,后续会更新思路以及附上注释的代码。?
3.AC代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=1e6+50;
const ll mod=1e9+7;
ll sum[maxn<<2],len[maxn<<2],lazy1[maxn<<2],lazy2[maxn<<2],lazylen[maxn<<2];
void build(ll id,ll l,ll r)
{
sum[id]=0;
len[id]=lazylen[id]=1;
lazy1[id]=lazy2[id]=0;
if(l==r)return;
ll mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
sum[id]=(sum[id<<1]+sum[id<<1|1])%mod;
len[id]=(len[id<<1]+len[id<<1|1])%mod;
}
void pushdown(ll id,ll l,ll r)
{
if(lazylen[id]==1)return;
lazy1[id<<1]=(lazy1[id]*lazylen[id<<1]%mod+lazy1[id<<1])%mod;
lazy1[id<<1|1]=(lazy1[id]*lazylen[id<<1|1]%mod+lazy1[id<<1|1])%mod;
lazy2[2*id]=(lazy2[2*id]*lazylen[id]%mod+lazy2[id])%mod;
lazy2[2*id+1]=(lazy2[2*id+1]*lazylen[id]%mod+lazy2[id])%mod;
int mid=(l+r)>>1;
sum[2*id]=(lazy1[id]*len[2*id]%mod*lazylen[id]%mod+sum[2*id]*lazylen[id]%mod+lazy2[id]*(mid-l+1))%mod;
sum[2*id+1]=(lazy1[id]*len[2*id+1]%mod*lazylen[id]%mod+sum[2*id+1]*lazylen[id]%mod+lazy2[id]*(r-mid))%mod;
len[2*id]=len[2*id]*lazylen[id]%mod*lazylen[id]%mod;
len[2*id+1]=len[2*id+1]*lazylen[id]%mod*lazylen[id]%mod;
lazylen[2*id]=(lazylen[2*id]*lazylen[id])%mod;
lazylen[2*id+1]=(lazylen[2*id+1]*lazylen[id])%mod;
lazy1[id]=0,lazy2[id]=0,lazylen[id]=1;
}
void update(ll L,ll R,ll k,ll id,ll l,ll r)
{
if(L==l&&R==r)
{
sum[id]=(k*len[id]%mod*10%mod+sum[id]*10%mod+k*(r-l+1)%mod)%mod;
len[id]=len[id]*100%mod;
lazy1[id]=(k*lazylen[id]%mod+lazy1[id])%mod;
lazy2[id]=(lazy2[id]*10+k)%mod;
lazylen[id]=lazylen[id]*10%mod;
return;
}
pushdown(id,l,r);
ll mid=(l+r)>>1;
if(R<=mid)update(L,R,k,2*id,l,mid);
else if(mid+1<=L)update(L,R,k,2*id+1,mid+1,r);
else
{
update(L,mid,k,2*id,l,mid);
update(mid+1,R,k,2*id+1,mid+1,r);
}
sum[id]=(sum[id<<1]+sum[id<<1|1])%mod;
len[id]=(len[id<<1]+len[id<<1|1])%mod;
}
ll query(ll L,ll R,ll id,ll l,ll r)
{
if(L==l&&R==r)return sum[id];
pushdown(id,l,r);
ll mid=(l+r)>>1;
if(R<=mid)return query(L,R,id<<1,l,mid);
else if(mid+1<=L)return query(L,R,id<<1|1,mid+1,r);
else return (query(L,mid,id<<1,l,mid)+query(mid+1,R,id<<1|1,mid+1,r))%mod;
}
int main()
{
ll t,Case=1;
scanf("%lld",&t);
while(t--)
{
printf("Case %d:\n",Case++);
ll n,m;
scanf("%lld %lld",&n,&m);
build(1,1,n);
while(m--)
{
char s[10];
scanf("%s",s);
if(s[0]=='w')
{
ll l,r,x;
scanf("%lld %lld %lld",&l,&r,&x);
update(l,r,x,1,1,n);
}
else
{
ll l,r;
scanf("%lld %lld",&l,&r);
printf("%lld\n",query(l,r,1,1,n));
}
}
}
return 0;
}
4.一点感受
线段树写起来代码量实在是太大了,需要修改的东西一多,就会出现以上巨宽的代码,鹅菜鸡本菜还是没有办法手撕线段树,非常自卑,加油啦啦啦啦啦。
还有一个就是,初学线段树的时候教我们的学长告诉我们说线段树那啥数组(具体啥数组真说不出来,好久不碰线段树了,以前都是能用树状数组绝对不用线段树的)需要开大一点,开多大呢?四倍就刚刚好,这让我感受到了线段树需要好大好大的空间,然鹅今天在手动复制另外一道主席树的题目的时候让我更加深刻地感受到了这一点,那道题就是开了很大的空间,用long long就会MLE,用int就很okk,这是我第一次用long long被卡掉,以前都是用int会在某些情况下wa掉,所以改了自己的习惯一直用long long了,以后碰到线段树相关的题目还是长个心眼吧
我一定会持续更新好这篇文哒!
我发4!
戏精啰嗦本性暴露
还有一点感悟就是?
感觉算法的优化吧
除非是特别天才的发明创造发现
否则本质感觉都是在以时间换空间,或是以空间换时间
让本戏精想到了能量守恒定律嘻嘻嘻
溜了溜了