题目链接:《夏摩山谷》 - 洛谷
题目背景
“只要结局完美,过去的种种都算好。” ——《山茶文具店》
题目描述
波波店主收到这样一份代笔
她被要求写下一个仅仅包含 00 到 99 字符串 ss ,但是她可能会对其中的一些数字不是很满意,会经常对某些位置重新修改
而这位顾客会经常来询问店主字符串 ss 下标从 xx 到 yy 形成的十进制数在模 10^9+7109+7 下是多少
店主对修改很适从,但是顾客的奇奇怪怪问题她就没办法解决了,请你帮她解决这个问题
输入格式
第一行一个整数 nn 和一个整数 qq,代表店主的字符串长度以及操作次数(操作包含修改和询问)
接下来一行是一个字符串 ss,代表店主写下的起始字符串
然后是 qq 行操作,opop xx yy
- op=1op=1:店主修改字符串下标 xx 的位置为 yy
- op=2op=2:顾客询问字符串 ss 下标从 xx 到 yy 形成的十进制数在模 10^9+7109+7 下是多少
字符串下标从 11 开始
每次修改会将字符串 ss 变成一个新的字符串,即下一次修改是在此基础上进行再次修改
输出格式
对于每次查询,输出一个数,表示字符串 ss 下标从 xx 到 yy 形成的十进制数在模 10^9+7109+7 下的数
输入输出样例
输入 #1复制
5 7 12345 2 1 5 2 2 3 1 2 1 2 1 5 2 2 3 1 5 1 2 1 5
输出 #1复制
12345 23 11345 13 11341
说明/提示
1\le n\le 10^51≤n≤105
1\le q\le 10^51≤q≤105
操作11:1\le x\le n,0\le y\le 91≤x≤n,0≤y≤9
操作22:1\le x\le y\le n1≤x≤y≤n
样例说明
第一次修改之前的两次询问,都是 s=12345s=12345 下的询问
询问11:[12345][12345]
询问22:1[23]451[23]45
第一次修改之后,s=11345s=11345
询问44:[11345][11345]
询问55:1[13]451[13]45
第二次修改之后,s=11341s=11341
询问77:[11341][11341]
思路:在更新的时候,我们观察u的左右子树和u有什么关系
比如u=12,那么左子树的sum就是1,右子树的sum就是2
那么u的sum就是左子树的sum*10的(右子树的长度)次幂+右子树的sum
void pushup(int u){
ll len=tr[u<<1|1].r -tr[u<<1|1].l +1;
tr[u].sum =(tr[u<<1].sum *ksm(10,len,mod)%mod+tr[u<<1|1].sum )%mod;
}
单点修改和建树操作还是按板子来就行
对查询操作我们要注意
当我们查询的u的区间被完全包含在我们需要查询的l-r中时
其实得到的值是u的sum*10的(r-u的r)次幂
比如12345
假设我们查的区间是2-5,但是当前结点的区间是2-3,那么我们应该得到的是2300
如果u不被l-r包含的话分别看看与左右子树有没有交集所得值相加就行了(因为左子树的权值我们在完全包含时就处理过了,直接加就行不用乘长度)
ll query(int u,int l,int r){
if(l<=tr[u].l &&r>=tr[u].r ){
ll len=r-tr[u].r ;
return tr[u].sum *ksm(10,len,mod)%mod;
}else{
int mid=tr[u].l +tr[u].r >>1;
ll v1=0,v2=0;
if(l<=mid)v1=query(u<<1,l,r);
if(r>mid)v2=query(u<<1|1,l,r);
return (v1+v2)%mod;
}
}
注意一下这个细节之后就可以ac啦~
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=1e9+7;
int n,m;
string a;
ll ksm(ll a,ll b,ll p){
ll res=1%p;
while(b){
if(b&1)res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
struct name{
int l,r;
ll sum;
}tr[N*4];
void pushup(int u){
ll len=tr[u<<1|1].r -tr[u<<1|1].l +1;
tr[u].sum =(tr[u<<1].sum *ksm(10,len,mod)%mod+tr[u<<1|1].sum )%mod;
// cout<<"l=="<<tr[u<<1].sum <<" r=="<<tr[u<<1|1].sum <<" sum=="<<tr[u].sum <<endl;
}
void build(int u,int l,int r){
if(l==r){
int op=a[l]-'0';
tr[u]={l,r,op};
}else{
tr[u]={l,r,0};
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int x,int v){
if(tr[u].l ==x&&tr[u].r ==x){
tr[u].sum =v;
}else{
int mid=tr[u].l +tr[u].r >>1;
if(x<=mid)modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
}
ll query(int u,int l,int r){
if(l<=tr[u].l &&r>=tr[u].r ){
ll len=r-tr[u].r ;
return tr[u].sum *ksm(10,len,mod)%mod;
}else{
int mid=tr[u].l +tr[u].r >>1;
ll v1=0,v2=0;
if(l<=mid)v1=query(u<<1,l,r);
if(r>mid)v2=query(u<<1|1,l,r);
return (v1+v2)%mod;
}
}
void sove(){
scanf("%d%d",&n,&m);
cin>>a;
a=" "+a;
build(1,1,n);
while(m--){
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1){
modify(1,l,r);
}else{
cout<<query(1,l,r)<<endl;
}
}
}
int main(){
int t=1;
// scanf("%d",&t);
while(t--){
sove();
}
return 0;
}