HDU 5068 Harry And Math Teacher 線段樹維護矩陣乘積
阿新 • • 發佈:2018-12-24
題意:相鄰的兩層樓之間有兩個門,每個門內都有一個樓梯,分別通向上一層的兩扇門。但是,門內的樓梯會轉換狀態。所有樓梯起始都是通的。在狀態轉後後,會從通變成不通,反之也可以。如果樓梯是不通的,那就不能從該樓梯到上一層。有以下兩種操作:1.修改X層第Y個門通向上一層的第Z個門的樓梯的狀態。2.查詢從第X層到第Y層的所有的方案數。
思路:因為查詢的是方案數,我們想到了DP。但是,題目中的是動態修改動態查詢,怎麼辦呢?因為是線性遞推,我們可以利用矩陣來計算方案數。
同時,因為矩陣滿足結合律,我們就可以利用線段樹來儲存成段的矩陣乘積。而修改就是單點修改了。
注意:雖然題目中明確要求用取模運算,但是在計算的過程中還是會爆int的,所以要用long long.
程式碼如下:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const ll MOD = 1000000007; const int MAX = 50010; struct Matrix{ ll a[2][2]; Matrix(){memset(a,0,sizeof(a));} Matrix operator * (const Matrix & A) const{ Matrix C; for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) for(int k = 0; k < 2; ++k) C.a[i][j] = (C.a[i][j] + a[i][k] * A.a[k][j]) % MOD; return C; } }; #define lson(o) (o<<1) #define rson(o) ((o<<1)|1) struct yy{ Matrix m; int l,r; } node[MAX<<3]; void pushup(int o) { node[o].m = node[lson(o)].m * node[rson(o)].m; } void build(int l, int r, int o) { node[o].l = l; node[o].r = r; if(l == r){ for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) node[o].m.a[i][j] = 1; return; } int mid = (l + r) >>1; build(l,mid,lson(o)); build(mid+1,r,rson(o)); pushup(o); } int x,y,z; void update(int x,int o) { if(node[o].l == node[o].r){ node[o].m.a[y][z] ^= 1; return; } int mid = (node[o].l + node[o].r) >> 1; if(x <= mid) update(x,lson(o)); else update(x,rson(o)); pushup(o); } Matrix query(int L,int R,int o) { if(L <= node[o].l && R >= node[o].r) return node[o].m; Matrix ans; ans.a[0][0] = ans.a[1][1] = 1; int mid = (node[o].l + node[o].r) >> 1; if(L <= mid) ans = ans * query(L,R,lson(o)); if(R > mid) ans = ans * query(L,R,rson(o)); return ans; } int main(void) { //freopen("in","r",stdin); int N,M; while(~scanf("%d%d", &N,&M)){ build(1,N-1,1); for(int i = 0; i < M; ++i){ int Q; scanf("%d", &Q); if(Q==1){ scanf("%d %d %d", &x,&y,&z); y--,z--; update(x,1); } else{ scanf("%d %d", &x,&y); Matrix ret = query(x,y-1,1); ll ans = 0; for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) ans = (ans + ret.a[i][j]) % MOD; printf("%I64d\n",ans); } } } return 0; }