K-方块掉落(线段树,维护4个参数)

通过线段树解决,需要在结点设置4个参数来维护答案。

用线段树的每一个结点表示从l到r的一段命令。

根据题意,在任意一段命令执行后,我们会得到几堆高度不同的方块,堆数由命令中‘B’的个数决定。显然,我们在合并两段相邻的命令时,合并后其执行效果与分别执行这两段命令的区别是执行后一段命令产生的第一堆会接在前一段命令的最后一堆上,且后一段命令的第一堆中的‘R’命令会额外复制前一段命令的最后一堆,我们需要设置并维护一些参数以便求取多复制的这一部分。

sum——表示执行该段命令后得到的方块数,即答案

bn——表示执行该段命令后最后一堆的方块数,用于计算重复部分的长度

rb——表示该段命令中在遇见第一个'B'前的'R'的个数(显然,没有‘B’时该参数就是该段‘R’的个数),用于计算重复次数

fb——表示该段是否有‘B’命令

显然,在合并ls和rs(左右儿子)时

sum 为 ls.sum + rs.sum + ls.bn * ( 2 ^ rs.rb -1 ),其中ls.bn * ( 2 ^ rs.rb -1 )是上文提到的重复部分。

bn分三种情况,当ls和rs的fb都为0,即他们都没有'B'命令时,此段命令执行后只有唯一一堆方块,我们只需要让bn = sum即可(sum已经维护并考虑了重复部分);若是rs的fb为0(右儿子只产生一堆),那么bn = ls.bn + rs.sum + ls.bn * (2^ rs.rb - 1),即左儿子的最后一堆加上接在上面的右儿子和额外的复制部分;当rs的fb为1(右儿子不止产生一堆),那么只需要简单的取 bn = rs.bn即可。

rb、fb只需要考虑左右儿子的fb即可得出,不多赘述。

AC代码如下:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
const ll MOD = 1e9+7;
int m, n, k, a, b;
string s;
ll quickPower(ll a, ll b, ll mod = MOD) {
	ll ans = 1, base = a;
	while (b > 0) {
		if (b & 1)
			(ans *= base) %= mod;

		(base *= base) %= mod;
		b >>= 1;
	}
	return ans;
}

struct segT {
#define ls id << 1
#define rs (id << 1)|1
	struct node {
		ll rb, bn, sum, fb;
	}t[N<<2];
	int ql, qr;
	char qv;
	node merge(node l, node r) {
		node res;
		res.sum = (l.sum + r.sum + l.bn * (quickPower(2, r.rb) - 1)) % MOD;
		if (r.fb == 0 && l.fb == 0) {
			res.bn = res.sum;
			res.fb = 0;
		}
		else {
			res.fb = 1;
			if (r.fb == 0)
				res.bn = (l.bn + r.sum + l.bn * (quickPower(2, r.rb) - 1)) % MOD;
			else
				res.bn = r.bn;
		}
		if (l.fb)
			res.rb = l.rb;
		else
			res.rb = l.rb + r.rb;
		return res;
	}
	void build(int l, int r,int id) {
		if (l == r) {
			t[id].sum = 1;
			if (s[l] == 'Y') {
				t[id].bn = 1;
				t[id].rb = 0;
				t[id].fb = 0;
			}
			else if (s[l] == 'B') {
				t[id].bn = 1;
				t[id].rb = 0;
				t[id].fb = 1;
			}
			else{
				t[id].bn = 1;
				t[id].rb = 1;
				t[id].fb = 0;
			}
			return;
		}
		int mid = (l + r) >> 1;
		build(l, mid, ls);
		build(mid + 1, r, rs);
		t[id] = merge(t[ls], t[rs]);
	}
	void updat(int l, int r, int id) {
		if (l >= ql && r <= qr) {
			if (qv == 'Y') {
				t[id].bn = 1;
				t[id].rb = 0;
				t[id].fb = 0;
			}
			else if (qv== 'B') {
				t[id].bn = 1;
				t[id].rb = 0;
				t[id].fb = 1;
			}
			else {
				t[id].bn = 1;
				t[id].rb = 1;
				t[id].fb = 0;
			}
			return;
		}
		int mid = (l + r) >> 1;
		if (qr <= mid) updat(l, mid, ls);
		else updat(mid + 1, r, rs);
		t[id] = merge(t[ls], t[rs]);
	}
	node query(int l, int r, int id) {
		if (l >= ql && r <= qr) {
			return t[id];
		}
		int mid = (l + r) >> 1;
		if (qr <= mid)
			return query(l, mid, ls);
		else if (ql > mid)
			return query(mid + 1, r, rs);
		return merge(query(l, mid, ls), query(mid + 1, r, rs));
	}
#undef ls
#undef rs
}tr;

int main()
{
	cin >> n >> m;
	cin >> s;
	s = ' ' + s;
	tr.build(1, n, 1);
	while (m--) {
		cin >> k;
		if (k == 1) {
			cin >> tr.ql >> tr.qv;
			tr.qr = tr.ql;
			tr.updat(1, n, 1);
		}
		else {
			cin >> tr.ql >> tr.qr;
			cout << tr.query(1, n, 1).sum << '\n';
		}

	}
}