codeforces 1252K 线段树维护矩阵

分析

对于操作一,相当于翻转,我们可以用异或去处理这个标记
对于操作二,即查询 [ L , R ] [L,R] [L,R]这个区间的结果
对于初始值 a , b {a,b} a,b,我们有 x 1 ∗ a + y 1 ∗ b , x 2 ∗ a + y 2 ∗ b {x1 * a + y1 * b, x2 * a + y2 * b} x1a+y1b,x2a+y2b,即 A , B {A,B} A,B
其实这个操作就是一个矩阵的变化
我们维护一个 2 × 2 2×2 2×2的矩阵
{ a b } ∗ { 1 0 1 1 } = { a + b b } \left\{ \begin{matrix} a & b \end{matrix} \right\} * \left\{ \begin{matrix} 1 & 0 \\ 1 & 1 \end{matrix} \right\}= \left\{ \begin{matrix} a+b & b \end{matrix} \right\} {ab}{1101}={a+bb}

{ a b } ∗ { 1 1 0 1 } = { a a + b } \left\{ \begin{matrix} a & b \end{matrix} \right\} * \left\{ \begin{matrix} 1 & 1 \\ 0 & 1 \end{matrix} \right\}= \left\{ \begin{matrix} a & a+b \end{matrix} \right\} {ab}{1011}={aa+b}

我们发现题目所给的查询操作可以看成维护区间矩阵的乘积
所以我们用线段树去维护区间矩阵积

#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T>
void out(T x) { cout << x << endl; }
ll fast_pow(ll a, ll b, ll p) {ll c = 1; while(b) { if(b & 1) c = c * a % p; a = a * a % p; b >>= 1;} return c;}
ll exgcd(ll a, ll b, ll &x, ll &y) { if(!b) {x = 1; y = 0; return a; } ll gcd = exgcd(b, a % b, y, x); y-= a / b * x; return gcd; }
const ll N = 1e5 + 10;
const ll mod = 1e9 + 7;
struct matrix
{
    ll mx[2][2];
    matrix(ll a = 1, ll b = 0, ll c = 0, ll d = 1)
    {
        mx[0][0] = a;
        mx[0][1] = b;
        mx[1][0] = c;
        mx[1][1] = d;
    }
    matrix operator * (const matrix b) const
    {
        matrix c = matrix(0, 0, 0, 0);
        for(ll i = 0; i < 2; i ++)
            for(ll j = 0; j < 2; j ++)
                for(ll k = 0; k < 2; k ++)
                    c.mx[i][j] = (c.mx[i][j] + mx[i][k] * b.mx[k][j] % mod) % mod;
        return c;
    }
    void mat_swap()
    {
        swap(mx[0][0], mx[1][1]);
        swap(mx[0][1], mx[1][0]);
    }
    void print()
    {
        cout << mx[0][0] << " " << mx[0][1] << endl;
        cout << mx[1][0] << " " << mx[1][1] << endl;
    }
}mat[N << 3];
ll lazy[N << 3];
ll n, q;
char str[N];
void push_up(ll rt)
{
    mat[rt] = mat[rt << 1] * mat[rt << 1 | 1];
}
void push_down(ll rt)
{
    if(lazy[rt])
    {
        mat[rt].mat_swap();
        lazy[rt << 1] ^= 1;
        lazy[rt << 1 | 1] ^= 1;
        lazy[rt] = 0;
    }
}
void build(ll l, ll r, ll rt)
{
    if(l == r)
    {
        if(str[l] == 'A')
            mat[rt] = matrix(1, 0, 1, 1);
        else if(str[l] == 'B')
            mat[rt] = matrix(1, 1, 0, 1);
        return ;
    }
    ll mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    push_up(rt);
}
void update(ll l, ll r, ll L, ll R, ll rt)
{
    push_down(rt);
    if(l > R || r < L)
        return ;
    if(L <= l && r <= R)
    {
        lazy[rt] ^= 1;
        push_down(rt);
        return ;
    }
    ll mid = (l + r) >> 1;
    update(l, mid, L, R, rt << 1);
    update(mid + 1, r, L, R, rt << 1 | 1);
    push_up(rt);
}
matrix query(ll l, ll r, ll L, ll R, ll rt)
{
    push_down(rt);
    if(l > R || r < L)
        return matrix();
    if(L <= l && r <= R)
        return mat[rt];
    ll mid = (l + r) >> 1;
    matrix m1 = query(l, mid, L, R, rt << 1);
    matrix m2 = query(mid + 1, r, L, R, rt << 1 | 1);
    return m1 * m2;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> q;
    cin >> (str + 1);
    build(1, n, 1);
    while(q --)
    {
        ll d;
        cin >> d;
        if(d == 1)
        {
            ll l, r;
            cin >> l >> r;
            update(1, n, l, r, 1);
        }
        else 
        {
            ll l, r, a, b;
            cin >> l >> r >> a >> b;
            matrix mm = query(1, n, l, r, 1);
            ll A = (a * mm.mx[0][0] % mod + b * mm.mx[1][0] % mod) % mod;
            ll B = (a * mm.mx[0][1] % mod + b * mm.mx[1][1] % mod) % mod;
            cout << A << " " << B << endl;
        }
    }
}

你可能感兴趣的:(矩阵,线段树)