1. 程式人生 > >HDU 5068 Harry And Math Teacher 線段樹維護矩陣乘積

HDU 5068 Harry And Math Teacher 線段樹維護矩陣乘積

題意:相鄰的兩層樓之間有兩個門,每個門內都有一個樓梯,分別通向上一層的兩扇門。但是,門內的樓梯會轉換狀態。所有樓梯起始都是通的。在狀態轉後後,會從通變成不通,反之也可以。如果樓梯是不通的,那就不能從該樓梯到上一層。有以下兩種操作: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;
}