Codeforces - 794F - Leha and security system
• 给n个数,两种操作
• 1. 将[l, r]上所有数中数位为x的都改为y
• 2. 求[l, r]上所有数的和
我们可以对每一个0~9每一个数位用线段树维护它的和(如
97919
中数位9的和是
10101
) ,求答案的时候就是
∑数位×数位的和
。
然后考虑如何维护lazy标记,这里需要对线段树上的操作有深刻的理解。
首先很自然地想到可以维护
lz[rt][i]
为一个将
rt
区间的数位
i
变成
标记下传很简单:
lz[son][i]=lz[rt][lz[son][i]]
。在下传后,
rt
的
lz
和
sum
应该更新,这样保证同一个操作只下传一次。答案可以通过
lz
和
sum
得到,所以下传的时候不需要更新儿子的
sum
。
然后 push \_ up
也是很好写的。之所以要用 push_up
是因为有些小区间在 update
的时候并没有对大区间进行更新。
如果对线段树操作理解深的话这题应该还是很好写的。。
#include<bits/stdc++.h>
#define lson (rt<<1)
#define rson (rt<<1|1)
using namespace std;
typedef long long ll;
const int N=1e5+7;
int lz[N<<2][10];
ll sum[N<<2][10],tmp[10];
void push_up(int rt)
{
for(int i=0;i<10;++i) sum[rt][i]=0;
for(int i=0;i<10;++i) sum[rt][lz[lson][i]]+=sum[lson][i];
for(int i=0;i<10;++i) sum[rt][lz[rson][i]]+=sum[rson][i];
}
void build(int rt,int l,int r)
{
for(int i=0;i<10;++i) lz[rt][i]=i,sum[rt][i]=0;
if(l==r)
{
int t,tmp=1;
scanf("%d",&t);
while(t) sum[rt][t%10]+=tmp,tmp*=10,t/=10;
return ;
}
int m=(l+r)>>1;
build(lson,l,m);
build(rson,m+1,r);
for(int i=0;i<10;++i) sum[rt][i]=sum[lson][i]+sum[rson][i];
push_up(rt);
}
void push_down(int rt)
{
for(int i=0;i<10;++i) lz[lson][i]=lz[rt][lz[lson][i]];
for(int i=0;i<10;++i) lz[rson][i]=lz[rt][lz[rson][i]];
memset(tmp,0,sizeof(tmp));
for(int i=0;i<10;++i) tmp[lz[rt][i]]+=sum[rt][i];
for(int i=0;i<10;++i) sum[rt][i]=tmp[i];
for(int i=0;i<10;++i) lz[rt][i]=i;
}
void update(int rt,int l,int r,int ql,int qr,int x,int y)
{
if(ql<=l&&qr>=r)
{
for(int i=0;i<10;++i) if(lz[rt][i]==x) lz[rt][i]=y;
return ;
}
push_down(rt);
int m=(l+r)>>1;
if(ql<=m) update(lson,l,m,ql,qr,x,y);
if(qr>m) update(rson,m+1,r,ql,qr,x,y);
push_up(rt);
}
ll query(int rt,int l,int r,int ql,int qr)
{
ll res=0;
if(ql<=l&&qr>=r)
{
for(int i=0;i<10;++i) res+=sum[rt][i]*lz[rt][i];
return res;
}
push_down(rt);
int m=(l+r)>>1;
if(ql<=m) res+=query(lson,l,m,ql,qr);
if(qr>m) res+=query(rson,m+1,r,ql,qr);
return res;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
build(1,1,n);
while(q--)
{
int op,l,r,x,y;
scanf("%d%d%d",&op,&l,&r);
if(op==1)
{
scanf("%d%d",&x,&y);
update(1,1,n,l,r,x,y);
}
else printf("%I64d\n",query(1,1,n,l,r));
}
return 0;
}