CF794F Leha and security system

\(\tt Link\)

口胡十秒钟,调题两小时。

好的其实是个不难的 \(\tt {}^{\ast}2800\)(自我安慰。


考虑线段树。节点维护十种信息代表 \(0,\cdots,9\) 的权和。

权是啥?个位权是 \(1\),十位权是 \(10\),百位权是 \(100\),以此类推。
比如 \(2627\)\(2\) 的权是 \(1010\)\(6\) 的权是 \(100\)\(7\) 的权是 \(1\)

于是一个节点代表的区间的和,就是 \(\sum\) 数字乘上其对应权。

我们发现有了这个权和,修改可以轻松转移。

考虑原来是 \(1243\)
\(1\)\(2\),这时把 \(1\) 的权加到 \(2\) 头上
\(2\) 再变 \(4\),这时再把 \(2\) 的权加到 \(4\) 头上。
完全没有问题,权和正确

考虑一个地方的修改。

我们对于线段树的节点维护 \(tag_i\) 代表数字 \(i\) 变成了什么。

打标记:\(\forall tag_i=x,tag_i\gets y\)

当然同时要把 \(x\) 的权和累加到 \(y\) 头上。

考虑懒标记下传。直接枚举每个 \(x\to y\) 的变换,然后修改?有问题。

比如 \(1008\),先有一次 \(1\to2\),再有一次 \(0\to1\)
最终有 \(tag_0=1,tag_1=2\)
直接暴力改所有 \(i\to tag_i\),这时 \(0\) 会变成 \(2\)

所以我们在懒标记下传前,先备份当前的 \(tag\) 以及权和。

然后懒标记下传的部分相比暴力改 \(i\to tag_i\) 略有变化。

using ll = long long;

#define rep(i,a,b) for(rg int i = (a);i <= (b);++i)
#define rg register
#define il inline

const int N = 1e5 + 5,S = N << 2;

int n,m;

ll T[10][S],tmp[2][10];
char tg[10][S],old[2][10];

#define lc (i << 1)
#define rc (lc | 1)
#define mid ((L + R) >> 1)

#define ls lc,L,mid
#define rs rc,mid + 1,R
#define id rg int i = 1,rg int L = 1,rg int R = n

il void psu(int i){
	rep(d,0,9) T[d][i] = T[d][lc] + T[d][rc];
}

il void psd(rg int i){
	rep(d,0,9){
		tmp[0][d] = T[d][lc];
		tmp[1][d] = T[d][rc];
		old[0][d] = tg[d][lc];
		old[1][d] = tg[d][rc];
	}
	rep(d,0,9) if(tg[d][i] != d){
		int x = d,y = tg[d][i];
		T[y][lc] += tmp[0][x]; T[x][lc] -= tmp[0][x];
		rep(d,0,9) if(old[0][d] == x) tg[d][lc] = y;
		T[y][rc] += tmp[1][x]; T[x][rc] -= tmp[1][x];
		rep(d,0,9) if(old[1][d] == x) tg[d][rc] = y;
		tg[d][i] = d;
	}
}

il void build(id){
	rep(d,0,9) tg[d][i] = d;
	if(L == R){
		int x = read(),cur = 1;
		while(x){
			T[x % 10][i] += cur;
			x /= 10; cur *= 10;
		}
		return;
	}
	build(ls); build(rs); psu(i);
}

il void upd(rg int l,rg int r,rg int x,rg int y,id){
	if(l <= L && R <= r){
		T[y][i] += T[x][i]; T[x][i] = 0;
		rep(d,0,9) if(tg[d][i] == x) tg[d][i] = y;
		return;
	}
	psd(i);
	if(l <= mid) upd(l,r,x,y,ls);
	if(r > mid) upd(l,r,x,y,rs);
	psu(i);
}

il ll qry(rg int l,rg int r,id){
	if(l <= L && R <= r){
		ll res = 0;
		rep(d,0,9) res += T[d][i] * d;
		return res;
	}
	psd(i);
	return (l <= mid ? qry(l,r,ls) : 0LL) + (r > mid ? qry(l,r,rs) : 0LL);
}

int main(){
	n = read(),m = read();
	build();
	while(m--){
		int op = read(),l = read(),r = read();
		if(op == 2) printf("%lld\n",qry(l,r));
		else { int x = read(),y = read(); if(x != y) upd(l,r,x,y); }
	}
	return 0;
}
posted @ 2022-08-17 21:15  One_Zzz  阅读(60)  评论(0)    收藏  举报