专栏文章
【题录】数据结构杂题
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min73e3h
- 此快照首次捕获于
- 2025/12/01 21:38 3 个月前
- 此快照最后确认于
- 2025/12/01 21:38 3 个月前
Lucky Numbers
题面
思路
考虑直接用线段树维护,每个节点维护 个大标记,每个大标记维护 个小标记,具体如下:
-
小标记:,,,。其中 表示总合法数量, 表示开头为 的合法数量, 表示结尾为 的合法数量, 表示开头为 且结尾为 的合法数量。
-
大标记:,,。其中 表示小于原序列的合法数量, 表示等于原序列的合法数量, 表示大于原序列的合法数量。
合并:
-
小标记:
-
大标记:其中, 是以小标记的合并方式将两个大标记的小标记合并,而 是直接将两个大标记的小标记相加。
叶子节点分类讨论后,按如上方式维护线段树即可。
代码
CPP#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
struct tag{
long long ans,b3,e1,b3e1;
};
tag operator + (tag x,tag y){
tag z;
z.ans=(x.ans+y.ans)%mod;
z.b3=(x.b3+y.b3)%mod;
z.e1=(x.e1+y.e1)%mod;
z.b3e1=(x.b3e1+y.b3e1)%mod;
return z;
}
//两个大标记相加为将其小标记相加
tag operator * (tag x,tag y){
tag z;
z.ans=(x.ans*y.ans-x.e1*y.b3%mod+mod)%mod;
z.b3=(x.b3*y.ans-x.b3e1*y.b3%mod+mod)%mod;
z.e1=(x.ans*y.e1-x.e1*y.b3e1%mod+mod)%mod;
z.b3e1=(x.b3*y.e1-x.b3e1*y.b3e1%mod+mod)%mod;
return z;
}
//两个大标记相乘为将其小标记合并
struct node{
tag l,e,g;
};
inline node merge(node x,node y){
node z;
z.l=x.e*y.l+x.l*(y.l+y.e+y.g);
z.e=x.e*y.e;
z.g=x.e*y.g+x.g*(y.l+y.e+y.g);
return z;
}
//大标记的合并
int n,q,a[100010];
node tree[400010];
inline void init(int x,int v){
tree[x].l.ans=v;
tree[x].e.ans=1;
tree[x].g.ans=9-v;
if(v<1)
{
tree[x].l.e1=0;
tree[x].e.e1=0;
tree[x].g.e1=1;
}
if(v==1)
{
tree[x].l.e1=0;
tree[x].e.e1=1;
tree[x].g.e1=0;
}
if(v>1)
{
tree[x].l.e1=1;
tree[x].e.e1=0;
tree[x].g.e1=0;
}
if(v<3)
{
tree[x].l.b3=0;
tree[x].e.b3=0;
tree[x].g.b3=1;
}
if(v==3)
{
tree[x].l.b3=0;
tree[x].e.b3=1;
tree[x].g.b3=0;
}
if(v>3)
{
tree[x].l.b3=1;
tree[x].e.b3=0;
tree[x].g.b3=0;
}
tree[x].l.b3e1=0;
tree[x].e.b3e1=0;
tree[x].g.b3e1=0;
}
//线段树叶子节点的分类讨论
inline void pushup(int x){
tree[x]=merge(tree[x*2],tree[x*2+1]);
}
void build(int l,int r,int x){
if(l==r)
{
init(x,a[l]);
return;
}
int mid=(l+r)>>1;
build(l,mid,x*2);
build(mid+1,r,x*2+1);
pushup(x);
}
void change(int l,int r,int x,int k,int v){
if(l==r)
{
init(x,v);
return;
}
int mid=(l+r)>>1;
if(k<=mid)change(l,mid,x*2,k,v);
else change(mid+1,r,x*2+1,k,v);
pushup(x);
}
node ask(int l,int r,int x,int ll,int rr){
if(l>=ll&&r<=rr)return tree[x];
int mid=(l+r)>>1;
if(rr<=mid)return ask(l,mid,x*2,ll,rr);
if(ll>mid)return ask(mid+1,r,x*2+1,ll,rr);
return merge(ask(l,mid,x*2,ll,rr),ask(mid+1,r,x*2+1,ll,rr));
}
//线段树维护标记
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
char c;
cin>>c;
a[i]=c-'0';
}
build(1,n,1);
printf("%lld\n",(tree[1].l.ans+tree[1].e.ans)%mod);
while(q--)
{
int op;
scanf("%d",&op);
if(op==1)
{
int l,r;
scanf("%d%d",&l,&r);
node s=ask(1,n,1,l,r);
printf("%lld\n",(s.l.ans+s.e.ans)%mod);
}
else
{
int k,v;
scanf("%d%d",&k,&v);
change(1,n,1,k,v);
}
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...