线段树维护矩阵:0920T4

正解为文艺平衡树维护矩阵,但我打不动,所以打了部分分

首先可以写成dp形式

然后又可以写成矩阵形式

然后矩阵显然支持结合律

所以可以拿线段树维护

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
//mt19937 rand(time(0));
//mt19937_64 rand(time(0));
//srand(time(0));
#define N 300010
//#define M
#define mo (int)(1e9+7)
int Mod(int a) {
	return (a%mo+mo)%mo; 
}
struct Martix {
	int a[4][4]; 
	void mem() {
		memset(a, 0, sizeof(a)); 
	}
	void init() {
		mem(); for(int i=1; i<=3; ++i) a[i][i]=1; 
	}
	void pre() {
		mem(); 	for(int i=1; i<=3; ++i) a[1][i]=1; 
	}
	int calc() {
		return (a[1][1]+a[1][2]+a[1][3])%mo; 
	}
	void print() {
		printf("ans : %lld %lld %lld\n", a[1][1], a[1][2], a[1][3]); 
	}
	void print_all() {
		printf("===\n"); 
		for(int i=1; i<=3; ++i, printf("\n")) 
			for(int j=1; j<=3; ++j) printf("%lld ", a[i][j]); 
	}
	Martix operator *( Martix &A)  {
		int i, j, k; 
		Martix ans; ans.mem(); 
//		print_all(); A.print_all(); 
		for(i=1; i<=3; ++i)
			for(j=1; j<=3; ++j)
				for(k=1; k<=3; ++k)
					ans.a[i][k]+=a[i][j]*A.a[j][k]%mo, 
					Mod(ans.a[i][k]); 
//		ans.print_all(); 
		return ans; 
	}
}c[4], ans, ps;
void Pre_Martix() {
	c[0].a[1][2]=1; c[0].a[1][3]=1; 
	c[0].a[2][3]=1; 
	
	c[2].a[1][1]=1; c[2].a[1][2]=1; c[2].a[1][3]=1; 
	c[2].a[2][2]=1; c[2].a[2][3]=1; 
	c[2].a[3][3]=1; 
	
	c[1].a[2][1]=1; 
	c[1].a[3][1]=1; c[1].a[3][2]=1; 
	
	c[3].a[1][1]=1; 
	c[3].a[2][1]=1; c[3].a[2][2]=1; 
	c[3].a[3][1]=1; c[3].a[3][2]=1; c[3].a[3][3]=1; 
	

}
int n, m, i, j, k, T;
int f[N][3], cm[N], q, l, r, rt; 
char s[N]; 

int calc() {
	ans.pre(); 
	for(i=1; i<n; ++i) {
		if(cm[i]==1) {
			if(cm[i]!=cm[i+1]) ans=ans*c[0]; 
			else ans=ans*c[2]; 
		}
		else {
			if(cm[i]!=cm[i+1]) ans=ans*c[1]; 
			else ans=ans*c[3]; 
		}	
	}
	return ans.calc(); 
}

int she1[4]={3, 2, 1, 0}; 
int she2[4]={2, 3, 0, 1}; 

struct Segment_tree {
	int tot, ls[N<<2], rs[N<<2]; 
	Martix s[N<<2], s1[N<<2]; 
	int g[N<<2], stg[N<<2]; 
	void build(int &k, int l, int r) {
		if(!k) k=++tot, s[k].init(), s1[k].init(); 
		if(l==r) return ;
		int mid=(l+r)>>1; 
		build(ls[k], l, mid); 
		build(rs[k], mid+1, r); 
	}
	
	void push_up(int k) {
		s[k]=s[ls[k]]*s[rs[k]]; 
		s1[k]=s1[ls[k]]*s1[rs[k]]; 
	}
	void jia(int k, int y) {
		s[k]=c[y]; s1[k]=c[y^1]; g[k]=y; 
	}
	void gai(int k, int *she) {
		g[k]=she[g[k]]; stg[k]=0; 
		s[k]=c[g[k]]; s1[k]=c[g[k]^1]; 
	}
	void Qu_gai(int k) {
		stg[k]^=1; g[k]^=1; swap(s[k], s1[k]); 
	}
	void push_down(int k) {
		if(stg[k]) {
			stg[ls[k]]^=1; stg[rs[k]]^=1; 
			g[ls[k]]^=1; g[rs[k]]^=1; 
			swap(s[ls[k]], s1[ls[k]]); 
			swap(s[rs[k]], s1[rs[k]]); 
			stg[k]=0; 
		}
	}	
	void add(int k, int l, int r, int x, int y) {
		if(l==r) return jia(k, y), void(); 
		int mid=(l+r)>>1; 
		if(x<=mid) add(ls[k], l, mid, x, y); 
		else add(rs[k], mid+1, r, x, y); 
		push_up(k); 
	}
	void Bian(int k, int l, int r, int x, int *she) {
		if(l==r) return gai(k, she), void(); 
		int mid=(l+r)>>1; 
		push_down(k); 
		if(x<=mid) Bian(ls[k], l, mid, x, she); 
		else Bian(rs[k], mid+1, r, x, she); 
		push_up(k); 
	}
	void qu(int k, int l, int r, int x, int y) {
		if(l>=x && r<=y) return Qu_gai(k), void(); 
		int mid=(l+r)>>1; 
		push_down(k); 
		if(x<=mid) qu(ls[k], l, mid, x, y); 
		if(y>=mid+1) qu(rs[k], mid+1, r, x, y); 
		push_up(k); 
	}
}Seg;

void suan() { //[1, n-1]
	for(i=1; i<n; ++i) {
		if(cm[i]==1) {
			if(cm[i]!=cm[i+1]) Seg.add(1, 1, n-1, i, 0); 
			else Seg.add(1, 1, n-1, i, 2); 
		}
		else {
			if(cm[i]!=cm[i+1]) Seg.add(1, 1, n-1, i, 1); 
			else Seg.add(1, 1, n-1, i, 3); 
		}	
	}
}

signed main()
{
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
		freopen("suffix.in", "r", stdin);
	freopen("suffix.out", "w", stdout);
//	T=read();
//	while(T--) {
//
//	}
	n=read(); q=read(); 
	for(i=1; i<n; ++i) cm[i]=read(); cm[n]=0; 
	Pre_Martix(); 
	if (n<=500) {
		printf("%lld\n", calc()); 
		while(q--) {
			scanf("%s", s+1); l=read(); r=read(); 
			if(s[1]=='F') {
				for(i=l; i<=r; ++i) cm[i]^=1; 
			}
			else {
				for(i=l, j=r; i<=j; ++i, --j) swap(cm[i], cm[j]); 
			}
			printf("%lld\n", calc()); 
		}
		return 0; 
	}
	Seg.build(rt, 1, n-1); 
	ans.pre(); 
	suan(); 
	ps=ans*Seg.s[1];  
	printf("%lld\n", ps.calc()); 
	while(q--) {
		scanf("%s", s+1); l=read(); r=read(); 
		if(s[1]=='F') {
			if(l-1>=1) Seg.Bian(1, 1, n-1, l-1, she2); 
			if(r<n) Seg.Bian(1, 1, n-1, r, she1); 
			if(l!=r) Seg.qu(1, 1, n-1, l, r-1); 
		}
		ps=ans*Seg.s[1]; 
		printf("%lld\n", ps.calc()); 
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值