2019-2020 ICPC, Asia Jakarta Regional Contest K. Addition Robot(线段树 + 矩阵乘法)

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Adding two numbers several times is a time-consuming task, so you want to build a robot. The robot should have a string S=S1S2…SNS=S1S2…SN of NN characters on its memory that represents addition instructions. Each character of the string, SiSi, is either 'A' or 'B'.

You want to be able to give QQ commands to the robot, each command is either of the following types:

  • 1 LL RR. The robot should toggle all the characters of SiSi where L≤i≤RL≤i≤R. Toggling a character means changing it to 'A' if it was previously 'B', or changing it to 'B' if it was previously 'A'.
  • 2 LL RR AA BB. The robot should call f(L,R,A,B)f(L,R,A,B) and return two integers as defined in the following pseudocode:
        function f(L, R, A, B):
          FOR i from L to R
            if S[i] = 'A'
              A = A + B
            else
              B = A + B
          return (A, B)
      

You want to implement the robot's expected behavior.

Input

Input begins with a line containing two integers: NN QQ (1≤N,Q≤1000001≤N,Q≤100000) representing the number of characters in the robot's memory and the number of commands, respectively. The next line contains a string SS containing NN characters (each either 'A' or 'B') representing the initial string in the robot's memory. The next QQ lines each contains a command of the following types.

  • 1 LL RR (1≤L≤R≤N1≤L≤R≤N)
  • 2 LL RR AA BB (1≤L≤R≤N1≤L≤R≤N; 0≤A,B≤1090≤A,B≤109)

There is at least one command of the second type.

Output

For each command of the second type in the same order as input, output in a line two integers (separated by a single space), the value of AA and BB returned by f(L,R,A,B)f(L,R,A,B), respectively. As this output can be large, you need to modulo the output by 10000000071000000007.

Example

input

Copy

5 3
ABAAA
2 1 5 1 1
1 3 5
2 2 5 0 1000000000

output

Copy

11 3
0 1000000000

Note

Explanation for the sample input/output #1

For the first command, calling f(L,R,A,B)f(L,R,A,B) causes the following:

  • Initially, A=1A=1 and B=1B=1.
  • At the end of i=1i=1, A=2A=2 and B=1B=1.
  • At the end of i=2i=2, A=2A=2 and B=3B=3.
  • At the end of i=3i=3, A=5A=5 and B=3B=3.
  • At the end of i=4i=4, A=8A=8 and B=3B=3.
  • At the end of i=5i=5, A=11A=11 and B=3B=3.

Therefore, f(L,R,A,B)f(L,R,A,B) will return (11,3)(11,3).

For the second command, string SS will be updated to "ABBBB".

For the third command, the value of AA will always be 00 and the value of BB will always be 10000000001000000000. Therefore, f(L,R,A,B)f(L,R,A,B) will return (0,1000000000)(0,1000000000).

题意:

有一个长度为n的只含‘A’ ‘B’的字符串。

两种操作, 1号操作, 将一个区间的内的A与B互换

2号操作询问区间内的值, 给出起始A, B

在该区间内遇到字符A, A = A + B,遇到字符B, B = B + A

问最后A, B的值为多少?

思路:

对于查询操作, 我们可以线段树套个矩阵乘法, 就可以得出答案了

对于修改操作, 我们在线段树内每个节点存两种矩阵,然后遇到修改时

交换两种矩阵即可。

\begin{bmatrix} A & B \end{bmatrix} * \begin{bmatrix} 1 &0 \\1 & 1 \end{bmatrix} = \begin{bmatrix} A + B & B \end{bmatrix}

\begin{bmatrix} A & B \end{bmatrix} * \begin{bmatrix} 1 &1 \\0 & 1 \end{bmatrix} = \begin{bmatrix} A & B + A \end{bmatrix}

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
#define hash_ 1000000009
#define Continue(x) { x; continue; }
#define Break(x) { x; break; }
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
struct M
{
	ll m[2][2];
	M()
	{
		memset(m, 0, sizeof m);
	}
}A, B;
M c[N * 4][2];
int lzy[N * 4];
char s[N];
M mul(M a, M b)
{
	M ans;
	for (int i = 0; i < 2; i++)
		for (int j = 0; j < 2; j++)
			for (int k = 0; k < 2; k++)
				ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j] % mod) % mod;
	return ans;
}
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
#define mid  ((L) + (R) >> 1)
void push_up(int x)
{
	c[x][0] = mul(c[ls][0], c[rs][0]);
	c[x][1] = mul(c[ls][1], c[rs][1]);
}
void pushDown(int x)
{
	if (lzy[x])
	{
		swap(c[ls][0], c[ls][1]);
		swap(c[rs][0], c[rs][1]);
		lzy[ls] ^= 1;
		lzy[rs] ^= 1;
		lzy[x] = 0;
	}
}
void build(int x, int L, int R)
{
	if (L == R)
	{
		if (s[L] == 'A')
			c[x][0] = A, c[x][1] = B;
		else
			c[x][0] = B, c[x][1] = A;
		return;
	}
	build(ls, L, mid);
	build(rs, mid + 1, R);
	push_up(x);
}
void update(int x, int L, int R, int ql, int qr)
{
	if (ql <= L && qr >= R)
	{
		swap(c[x][0], c[x][1]);
		lzy[x] ^= 1;
		return;
	}
	pushDown(x);
	if (ql <= mid)
		update(ls, L, mid, ql, qr);
	if (qr > mid)
		update(rs, mid + 1, R, ql, qr);
	push_up(x);
}
void query(int x, int L, int R, int ql, int qr, M& ans)
{
	if (ql <= L && qr >= R)
	{
		ans = mul(ans, c[x][0]);
		return;
	}
	pushDown(x);
	if (ql <= mid)
		query(ls, L, mid, ql, qr, ans);
	if (qr > mid)
		query(rs, mid + 1, R, ql, qr, ans);
	push_up(x);
}
int main()
{
#ifdef LOCAL
	freopen("D:/input.txt", "r", stdin);
#endif
	A.m[0][0] = A.m[1][0] = A.m[1][1] = B.m[0][0] = B.m[0][1] = B.m[1][1] = 1;
	int n, q;
	scanf("%d%d", &n, &q);
	scanf("%s", s + 1);
	build(1, 1, n);
	while (q--)
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int L, R;
			scanf("%d%d", &L, &R);
			update(1, 1, n, L, R);
		}
		else
		{
			int L, R, A, B;
			scanf("%d%d%d%d", &L, &R, &A, &B);
			M base, ans;
			ans.m[0][0] = ans.m[1][1] = 1;
			base.m[0][0] = A; base.m[0][1] = B;
			query(1, 1, n, L, R, ans);
			base = mul(base, ans);
			printf("%lld %lld\n", base.m[0][0], base.m[0][1]);
		}
	}
	return TIME;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值