【线段树】 HDOJ 5068 Harry And Math Teacher

线段树+矩阵。。。。


我们可以把第i层跟第i+1层之间楼梯的通断性构造成一个2*2的通断性矩阵,1表示通,0表示不通。那么从第a层到第b层,就是将a到b-1的通断性矩阵连乘起来,然后将得到的答案矩阵上的每个元素加起来即为方案数。想到矩阵的乘法是满足结合律的,那么我们可以用线段树来维护矩阵的乘积。每次我们只会修改某一个楼梯的通断性,所以就只是简单的线段树单点更新,成段求乘积而已。
整体复杂度
   
    222nlogn
   

#include <iostream>
#include <queue> 
#include <stack> 
#include <map> 
#include <set> 
#include <bitset> 
#include <cstdio> 
#include <algorithm> 
#include <cstring> 
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 50005
#define maxm 2000005
#define eps 1e-10
#define mod 1000000007
#define INF 1e9
#define lowbit(x) (x&(-x))
#define mp make_pair
#define ls o<<1
#define rs o<<1 | 1
#define lson o<<1, L, mid 
#define rson o<<1 | 1, mid+1, R 
typedef long long LL;
typedef unsigned long long ULL;
//typedef int LL;
using namespace std;

struct matrix
{
	LL mat[3][3];
	matrix operator * (const matrix& a) const {
		matrix res;
		for(int i = 1; i <= 2; i++)
			for(int j = 1; j <= 2; j++) {
				LL t = 0;
				for(int k = 1; k <= 2; k++)
					t = (t + mat[i][k] * a.mat[k][j]) % mod;
				res.mat[i][j] = t;
			}
		return res;
	}
}sum[maxn << 2], one;
int n, m;

void pushup(int o)
{
	sum[o] = sum[ls] * sum[rs];
}
void build(int o, int L, int R)
{
	if(L == R) {
		sum[o].mat[1][1] = sum[o].mat[1][2] = 1;
		sum[o].mat[2][1] = sum[o].mat[2][2] = 1;
		return;
	}
	int mid = (L + R) >> 1;
	build(lson);
	build(rson);
	pushup(o);
}

void updata(int o, int L, int R, int q, int a, int b)
{
	if(L == R) {
		sum[o].mat[a][b] ^= 1;
		return;
	}
	int mid = (L + R) >> 1;
	if(q <= mid) updata(lson, q, a, b);
	else updata(rson, q, a, b);
	pushup(o);
}

matrix query(int o, int L, int R, int ql, int qr)
{
	if(ql <= L && qr >= R) return sum[o];
	int mid = (L + R) >> 1;
	matrix ans = one;
	if(ql <= mid) ans = ans * query(lson, ql, qr);
	if(qr > mid)  ans = ans * query(rson, ql, qr);
	return ans;
}

void work(void)
{
	build(1, 1, n);
	one.mat[1][1] = one.mat[2][2] = 1;
	one.mat[1][2] = one.mat[2][1] = 0;
	int a, b, c, k;
	while(m--) {
		scanf("%d", &k);
		if(!k) {
			scanf("%d%d", &a, &b);
			matrix tt = query(1, 1, n, a, b-1);
			LL ans = 0;
			for(int i = 1; i <= 2; i++)
				for(int j = 1; j <= 2; j++)
					ans = (ans + tt.mat[i][j]) % mod;
			printf("%I64d\n", ans);
		}
		else {
			scanf("%d%d%d", &a, &b, &c);
			updata(1, 1, n, a, b, c);
		}
	}
}

int main(void)
{
	while(scanf("%d%d", &n, &m)!=EOF) work();

	return 0;
}


你可能感兴趣的:(HDU)