codeforces 1252K Addition Robot【線段樹+矩陣乘法】

題目大意

給你一個串 包含AB兩種元素,進行以下兩種操作

1、給定一個區間[l,r][l,r] 將 A 變成 B,B 變成 A

2、給定一個查詢區間 [l,r][l,r] 以及 兩個數 x,y

在區間 [l,r][l,r]中如果 s[i]=As[i] =A 那麼 x = x+y
否則 y=x+y

查詢這個區間最後的x,y分別是多少

題目分析

剛拿到這個題有些無從分析

我們考慮
x=x+y 、 y=x+y
這兩個操作,發現可以寫成矩陣的形式

在這裏插入圖片描述
所以,我們考慮線段樹維護區間矩陣乘積

那麼當我們在進行修改的時候,對於一個區間而言,其實乘積只有可能有兩種。所以每個點維護這兩種乘積即可。

如果修改區間的話,就交換這兩種乘積。然後修改父親結點即可。

代碼詳解

#include <bits/stdc++.h>
using namespace std;
const int maxn =4e5+50;
const int mod = 1e9+7;
typedef long long ll;
string s;
struct Mat
{
	int a[2][2];
};
Mat A,B,E;
Mat mul(Mat x,Mat y)
{
	Mat t;
	
	for(int i=0;i<2;i++)
		for(int j=0;j<2;j++)
		{
			t.a[i][j]=0;
			for(int k=0;k<2;k++)
				t.a[i][j] += ((ll)x.a[i][k] * (ll)y.a[k][j])%mod;
				t.a[i][j] %=mod;
		}
	 return t;
}
struct Node
{
	int l,r;
	Mat w[2];
	int flag = 0;
}node[maxn];
void pt(int root)
{
	cout<<root<<endl;
	cout<<node[root].l<<" "<<node[root].r<<endl;
	for(int i=0;i<2;i++)
	{
		for(int j=0;j<2;j++)
		{
			cout<<node[root].w[0].a[i][j]<<" ";
		}
		cout<<endl;
	}
}
void pushup(int root)
{
	node[root].w[0] =mul(node[root*2].w[0],node[root*2+1].w[0]);
	node[root].w[1] =mul(node[root*2].w[1],node[root*2+1].w[1]);
}
void pushdown(int root)
{
	if(node[root].flag)
	{
		node[root*2].flag^=1;
		swap(node[root*2].w[0],node[root*2].w[1]);
		node[root*2+1].flag^=1;
		swap(node[root*2+1].w[0],node[root*2+1].w[1]);
		node[root].flag^=1;
	}
}
void build(int root,int l,int r)
{
	if(l>r) return ;
	node[root].l = l;
	node[root].r = r;
	node[root].flag=0;
	if(l==r) 
	{
		if(s[l-1]=='A') 
		node[root].w[0] =A,node[root].w[1] = B;
		else node[root].w[0]=B,node[root].w[1] =A;
		//pt(root);
		return;
	} 
	int mid = (l+r)/2;
	build(root*2,l,mid);
	build(root*2+1,mid+1,r);
	pushup(root);
	//pt(root);
}
void update(int root,int st,int ed)
{

	int l = node[root].l;
	int r = node[root].r;
	//cout<<st<<" "<<ed<<" "<<l<<" "<<r<<endl;
	if(st>r||ed<l) return;
	if(st<=l&&ed>=r)
	{
		node[root].flag^=1;
		swap(node[root].w[0],node[root].w[1]);
		//pt(root);
		return;
	}
	pushdown(root);
	update(root*2,st,ed);
	update(root*2+1,st,ed);
	pushup(root);
	//pt(root);
} 
Mat query(int root,int st,int ed)
{
	int l = node[root].l;
	int r = node[root].r;
	if(l>ed||r<st) return E;
	if(st<=l&&ed>=r)
	{
		return node[root].w[0]; 
	} 
	Mat x=E;
	pushdown(root);
	x=mul(x,query(root*2,st,ed));
	x=mul(x,query(root*2+1,st,ed));
	pushup(root);
	return x;
}
int main()
{
	int n,q;
	scanf("%d%d",&n,&q);
	cin>>s;
	A.a[0][0] = 1; A.a[0][1] = 0; A.a[1][0] = 1; A.a[1][1] = 1;
	B.a[0][0] = 1; B.a[0][1] = 1; B.a[1][0] = 0; B.a[1][1] = 1;
	E.a[0][0] = 1; E.a[0][1] = 0; E.a[1][0] = 0; E.a[1][1] = 1;
	build(1,1,n);
	for(int i=1;i<=q;i++)
	{
		int op;
		scanf("%d",&op);
		if(op==1) 
		{
			int l,r;
			scanf("%d%d",&l,&r);
			update(1,l,r);
		}
		if(op==2)
		{
			int l,r,x,y;
			scanf("%d%d%d%d",&l,&r,&x,&y);
			Mat t = query(1,l,r);
			ll le =((ll)t.a[0][0]*(ll)x%mod+(ll)t.a[1][0]*(ll)y%mod)%mod;
			ll ri = ((ll)t.a[0][1]*(ll)x%mod+ (ll) t.a[1][1]*(ll)y%mod)%mod;
			printf("%I64d %I64d\n",le,ri); 
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章