您的位置:首页 > 其它

HDU 5068 Harry And Math Teacher 线段树+矩阵乘法

2014-10-27 19:32 344 查看
题意:

  一栋楼有n层,每一层有2个门,每层的两个门和下一层之间的两个门之间各有一条路(共4条)。

  有两种操作:

  0 x y : 输出第x层到第y层的路径数量。

  1 x y z : 改变第x层 的 y门 到第x+1层的 z门的通断情况。

思路:

  门之间的路径数可以用矩阵来表示,经过的中间层可以用矩阵乘积表示。 所以用线段树维护矩阵乘积即可。

代码:

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <cctype>
#include <time.h>

using namespace std;

typedef __int64 ll;

const int INF = 1<<30;
const int MAXN = 5e4+55;
const ll MOD = 1e9+7;

struct Matrix {
ll a[2][2];

Matrix() {}

Matrix(int x) {
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
a[i][j] = i==j ? x : 0;
}

Matrix operator * (const Matrix &x) {
Matrix res;
for (int i = 0; i < 2; i ++) {
for (int j = 0; j < 2; j++) {
res.a[i][j] = 0;
for (int k = 0; k < 2; k++) {
res.a[i][j] = (res.a[i][j]+a[i][k]*x.a[k][j])%MOD;
}
}
}
return res;
}

inline ll sum() {
return (a[0][0] + a[0][1] + a[1][0] + a[1][1])%MOD;
}

inline void update(int i, int j) {
a[i][j] ^= 1;
}

inline void init() {
a[0][0] = a[0][1] = a[1][0] = a[1][1] = 1;
}
void output() {
puts("Matrix: ");
for (int i = 0; i < 2; i ++) {
for (int j = 0; j < 2; j++)
printf("%I64d ", a[i][j]);
puts("");
}
}
};

Matrix a[MAXN<<2];
int id[MAXN];

#define LS l, m, p<<1
#define RS m+1, r, p<<1|1

inline void pushUp(int p) {
a[p] = a[p<<1]*a[p<<1|1];
}

void build(int l, int r, int p) {
if (l==r) {
a[p].init();
id[l] = p;
return ;
}
int m = (l+r) >> 1;
build(LS);
build(RS);
pushUp(p);
}

void update(int p, int i, int j) {
p = id[p];
a[p].update(i, j);
p >>= 1;
while (p>0) {
pushUp(p);
p >>= 1;
}
}

Matrix query(int L, int R, int l, int r, int p) {
if (L<=l&&r<=R)
return a[p];

int m = (l+r)>>1;

Matrix res(1);
if (L<=m) res = res * query(L, R, LS);
if (m <R) res = res * query(L, R, RS);

return res;
}

int main() {
#ifdef Phantom01
freopen("1003.txt", "r", stdin);
#endif //Phantom01

int n, m;
int op, x, y, z;
while (scanf("%d%d", &n, &m)!=EOF) {
n--;
build(1, n, 1);
while (m--) {
scanf("%d", &op);
if (op==0) {
scanf("%d%d", &x, &y);
y--;
printf("%I64d\n", query(x, y, 1, n, 1).sum());
} else {
scanf("%d%d%d", &x, &y, &z);
y--; z--;
update(x, y, z);
}
}
}

return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: