2021ccpc 桂林 B.A Plus B Problem

B. A Plus B Problem

JB gets a machine that can solve “A Plus B Problem” and feels curious about the mechanism. He hears that you are proficient in competitive programming and have learned many advanced data structures and algorithms such as Link-Cut tree, Lagrange Inversion formula, Sweepline Mo, and so on. Hence, he asks you to help implement a program that can solve “A Plus B Problem” as same as the machine.

The machine consists of 3×n digits. The digits of the first two rows can be changed arbitrarily, and the third row always equals the decimal sum of the first two rows. The third row only consists of the lowest n digits even if the sum exceeds n digits.

For example, when n=5, the three rows can be “01234”, “56789”, “58023” or “56789”, “58023”, “14812”.

To test your function, you are given q queries. In the i-th query, the ci-th digit of the ri-th row is updated to di (the digit may not change). Because the digits are too many and JB has no time to check your answer, he only asks you to find the ci-th digit of the third row after the query and how many digits of the machine change in the query.

Input
The first line contains two integers n and q (1≤n,q≤106).

The second line contains a string consisting of n digits, representing the first row of the machine.

The third line contains a string consisting of n digits, representing the second row of the machine.

There are q lines in the following. The i-th of the following line consists of three integers ri,ci and di (1≤ri≤2, 1≤ci≤n, 0≤di≤9).

Output
Output q lines. In the i-th line, output two integers - the ci-th digit of the third row after the query and how many digits of the machine change in the query.

Example
input
5 5
01234
56789
2 1 0
2 2 1
2 3 2
2 4 3
2 5 4
output
0 2
3 2
5 3
7 3
8 3
Note
In the example, the initial rows are “01234”, “56789”, “58023”.

After the 1-st query, the rows are “01234”, “06789”, “08023”.

After the 2-nd query, the rows are “01234”, “01789”, “03023”.

After the 3-th query, the rows are “01234”, “01289”, “02523”.

After the 4-th query, the rows are “01234”, “01239”, “02473”.

After the 5-th query, the rows are “01234”, “01234”, “02468”.

解题思路

线段树维护两个值,suf_0和suf_1,分别表示区间[l,r]中从r开始向前0的个数和9的个数,剩下的就好写多了

#include <bits/stdc++.h>

#define ll long long
#define pf(x) cout<<"("<<__LINE__<<")"<<#x<<" ="<<x<<endl

using namespace std;

const int N = 1e6+7;

int a[3][N],w[N];
int u,n,m;
struct node{
	int l,r,v;
	int suf[2];
	int lazy[2];
}t[N<<2];

node operator + (const node& a,const node& b){
	node c;
	c.l = a.l;
	c.r = b.r;
	if(b.suf[0] == b.r - b.l + 1) c.suf[0] = a.suf[0] + b.suf[0];
	else c.suf[0] = b.suf[0];
	
	if(b.suf[1] == b.r - b.l + 1) c.suf[1] = a.suf[1] + b.suf[1];
	else c.suf[1] = b.suf[1];
	return c;
}
void pushup(int x){
	node &c = t[x];
	node &a = t[x << 1];
	node &b = t[x << 1 | 1];
	
	if(b.suf[0] == b.r - b.l + 1) c.suf[0] = a.suf[0] + b.suf[0];
	else c.suf[0] = b.suf[0];
	
	if(b.suf[1] == b.r - b.l + 1) c.suf[1] = a.suf[1] + b.suf[1];
	else c.suf[1] = b.suf[1];
}
void build(int l,int r,int x = 1){
	t[x] = {l,r,w[l],0,0,0,0};
	if(l == r){
	    if(w[l] == 0) t[x].suf[0] = 1;
	    if(w[l] == 9) t[x].suf[1] = 1;
	    return ;
	}
	int mid = l + r >> 1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
	pushup(x);
}
void pushdown(node &op, int tag_0, int tag_9){
	if(tag_0){
		op.v = 0;
		op.suf[0] = op.r - op.l + 1;
		op.suf[1] = 0;
		op.lazy[0] = 1;
		op.lazy[1] = 0;
	}
	if(tag_9){
		op.v = 9;
		op.suf[1] = op.r - op.l + 1;
		op.suf[0] = 0;
		op.lazy[1] = 1;
		op.lazy[0] = 0;
	}
}
void pushdown(int x){
	node& p = t[x];
    pushdown(t[x << 1], p.lazy[0], p.lazy[1]);
    pushdown(t[x << 1 | 1], p.lazy[0], p.lazy[1]);
    p.lazy[1] = p.lazy[0] = 0;
}
int query(int l,int x = 1) {
    if (t[x].l == t[x].r) return t[x].v;
    pushdown(x);
    int mid = t[x].l + t[x].r >> 1;
    if (l <= mid) return query(l, x << 1);
    else return query(l, x << 1 | 1);
}
node query_suff(int l,int r,int x = 1){
	if(l <= t[x].l && t[x].r <= r) return t[x];
	int mid = t[x].l + t[x].r >> 1;
	if(l > mid) return query_suff(l,r,x << 1|1) ;
	else if(r <= mid) return query_suff(l,r, x<< 1);
	return query_suff(l,mid, x << 1) + query_suff(mid+1,r,x<< 1|1);
}
void modify(int l,int y,int x = 1){
	if (t[x].l == t[x].r) {
        t[x].v = y;
        t[x].suf[0] = (y == 0);
        t[x].suf[1] = (y == 9);
        return;
    }
    pushdown(x);
    int mid = (t[x].l + t[x].r) >> 1;
    if (l <= mid) modify(l, y,x << 1);
    else modify(l, y, x << 1 | 1);
    pushup(x);
}
void modify_val(int l,int r,int c,int x = 1){
	if(l <= t[x].l && r >= t[x].r){
		if(c == 0) pushdown(t[x],1,0);
		if(c == 9) pushdown(t[x],0,1);
		return ;
	}
	pushdown(x);
	int mid = t[x].l + t[x].r >> 1;
	if(l <= mid) modify_val(l,r,c,x << 1);
	if(r > mid) modify_val(l,r,c,x << 1 | 1);
	pushup(x);
}
void solve(){
	scanf("%d %d",&n,&m);
	for(int i = 1; i <= n; i ++) scanf("%1d",&a[1][i]);
	for(int i = 1; i <= n; i ++) scanf("%1d",&a[2][i]);
    for(int i = n; i >= 1; i --){
    	w[i] = a[1][i] + a[2][i] + u;
    	u = w[i] / 10, w[i] %= 10;
	}
	build(1,n);
	while(m--){
		int r,c,d;
		scanf("%d %d %d",&r,&c,&d);
		d = d - a[r][c];
		a[r][c] += d;
		int val = query(c) + d;
		int ans1,ans2;
		if(d == 0) {
			ans1 = val,ans2 = 0; 
		}
		else if(val >= 0 && val <= 9 || c == 1){
			val = (val + 100) % 10;
			modify(c,val);
			ans1 = val,ans2 = 2;
		}
		else if(val > 9){	
			int len = query_suff(1,c-1).suf[1];
			ans1 = val - 10, ans2 = len + 2;
			modify(c,val-10);
			if(len) modify_val(c-len,c-1,0);
			if(c - len - 1 >= 1){
				int tmp = query(c - len - 1);
				modify(c-len-1,tmp+1);
				ans2 ++;
			}
		}
		else{			
			int len = query_suff(1,c-1).suf[0];
			ans1 = val + 10, ans2 = len + 2;
			modify(c,val+10);
			if(len) modify_val(c-len,c-1,9);
			if(c-len-1 >= 1){
				int tmp = query(c-len-1);
				modify(c-len-1,tmp-1);
				ans2++;
			}
		}
		cout << ans1 <<" "<<ans2<<'\n';
	}
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值