2019 ICPC Asia Jakarta Regional Contest K. Addition Robot 线段树+矩阵乘法

原题链接:https://codeforces.ml/problemset/problem/1252/K

题意

有一个长度为N的字符串,只含有AB两种字符,接下来有2种操作

  1. l r 将区间[l, r]内的A变成B,B变成A
  2. l r a b 在区间[l, r]内,如果遇到A,a变成a和b之和,反之,b变成a和b之和,并输出最终的a b

分析

第一个操作区间翻转可以用线段树轻松维护,但第二个操作有些棘手。

学过矩阵乘法的同学都知道

遇到A其实就相当于(a,b) * (1 0 1 1)
遇到B其实就相当于(a,b) * (1 1 0 1)

这样处理的话我们可以在建线段树的时候就处理好矩阵

然后再看第一个操作,有两种方法

  1. 直接对当前答案矩阵转置
  2. 预处理两颗线段树,一颗存翻转前的,一颗存翻转后的

Code(直接转置763 ms)

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define re register
#define fi first
#define se second
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
struct Matrix {
    ll a[2][2];
    inline Matrix operator * (const Matrix& rhs) {
        Matrix ret;
        memset(&ret, 0, sizeof ret);
        for (int i = 0; i <= 1; i++)
            for (int j = 0; j <= 1; j++)
                for (int k = 0; k <= 1; k++)
                    ret.a[i][j] = (ret.a[i][j] + a[i][k] * rhs.a[k][j] % MOD) % MOD;
        return ret;
    }
}mp;
struct Node {
    int l, r;
    int tag;
    Matrix sum;
}t[N<<2];
string s;
 
void push_up(int u) {
    t[u].sum = t[u<<1].sum * t[u<<1|1].sum;
}
void push_down(int u) {
    if (t[u].tag) {
        t[u<<1].tag ^= t[u].tag;
        t[u<<1|1].tag ^= t[u].tag;
        swap(t[u<<1].sum.a[0][0], t[u<<1].sum.a[1][1]);
        swap(t[u<<1].sum.a[1][0], t[u<<1].sum.a[0][1]);
        swap(t[u<<1|1].sum.a[0][0], t[u<<1|1].sum.a[1][1]);
        swap(t[u<<1|1].sum.a[1][0], t[u<<1|1].sum.a[0][1]);
        t[u].tag = 0;
    }
}
void build(int u, int l, int r) {
    t[u].l = l, t[u].r = r, t[u].tag = 0;
    if (l == r) {
        if (s[l-1] == 'A') {
            t[u].sum.a[0][0] = 1;
            t[u].sum.a[0][1] = 0;
            t[u].sum.a[1][0] = 1;
            t[u].sum.a[1][1] = 1;
        } else {
            t[u].sum.a[0][0] = 1;
            t[u].sum.a[0][1] = 1;
            t[u].sum.a[1][0] = 0;
            t[u].sum.a[1][1] = 1;
        }
        return;
    }
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1|1, mid+1, r);
    push_up(u);
}
void modify(int u, int ql, int qr) {
    if (ql <= t[u].l && qr >= t[u].r) {
        swap(t[u].sum.a[0][0], t[u].sum.a[1][1]);
        swap(t[u].sum.a[0][1], t[u].sum.a[1][0]);
        t[u].tag ^= 1;
        return;
    }
    push_down(u);
    int mid = (t[u].l + t[u].r) >> 1;
    if (ql <= mid) modify(u<<1, ql, qr);
    if (qr > mid) modify(u<<1|1, ql, qr);
    push_up(u);
}
Matrix query(int u, int ql, int qr) {
    if (ql <= t[u].l && qr >= t[u].r) return t[u].sum;
    int mid = (t[u].l + t[u].r) >> 1;
    push_down(u);
    Matrix ret;
    ret.a[0][0] = 1;
    ret.a[0][1] = 0;
    ret.a[1][0] = 0;
    ret.a[1][1] = 1;
    if (ql <= mid) ret = ret * query(u<<1, ql, qr);
    if (qr > mid) ret = ret * query(u<<1|1, ql, qr);
    return ret;
}
void solve() {
    int n, m; cin >> n >> m;
    cin >> s;
    build(1, 1, n);
    for (int i = 1; i <= m; i++) {
        int opt, x, y; cin >> opt >> x >> y;
        if (opt == 1) modify(1, x, y);
        else {
            int a, b; cin >> a >> b;
            Matrix ret = query(1, x, y), ans;
            ans.a[0][0] = a;
            ans.a[0][1] = b;
            ans = ans * ret;
            printf("%lld %lld\n", ans.a[0][0], ans.a[0][1]);
        }
    }
}
 
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

Code(开两颗线段树858 ms)

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define re register
#define fi first
#define se second
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
struct Matrix {
    ll a[2][2];
    Matrix (){memset(a, 0, sizeof a);}
    inline Matrix operator * (const Matrix& rhs) {
        Matrix ret;
        memset(&ret, 0, sizeof ret);
        for (int i = 0; i <= 1; i++)
            for (int j = 0; j <= 1; j++)
                for (int k = 0; k <= 1; k++)
                    ret.a[i][j] = (ret.a[i][j] + a[i][k] * rhs.a[k][j] % MOD) % MOD;
        return ret;
    }
}A, B;
void init() {
    A.a[0][0] = A.a[1][0] = A.a[1][1] = 1;
    B.a[0][0] = B.a[0][1] = B.a[1][1] = 1;
}
int tag[N<<2];
Matrix sum[N<<2][2];
string s;

void push_up(int u) {
    sum[u][0] = sum[u<<1][0] * sum[u<<1|1][0];
    sum[u][1] = sum[u<<1][1] * sum[u<<1|1][1];
}
void push_down(int u) {
    if (tag[u]) {
        tag[u<<1] ^= tag[u];
        tag[u<<1|1] ^= tag[u];
        swap(sum[u<<1][0], sum[u<<1][1]);
        swap(sum[u<<1|1][0], sum[u<<1|1][1]);
        tag[u] = 0;
    }
}
void build(int u, int l, int r) {
    tag[u] = 0;
    if (l == r) {
        if (s[l-1] == 'A') {
            sum[u][0] = A;
            sum[u][1] = B;
        } else {
            sum[u][0] = B;
            sum[u][1] = A;
        }
        return;
    }
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1|1, mid+1, r);
    push_up(u);
}
void modify(int u, int ql, int qr, int l, int r) {
    if (ql <= l && qr >= r) {
        swap(sum[u][0], sum[u][1]);
        tag[u] ^= 1;
        return;
    }
    push_down(u);
    int mid = (l + r) >> 1;
    if (ql <= mid) modify(u<<1, ql, qr, l, mid);
    if (qr > mid) modify(u<<1|1, ql, qr, mid+1, r);
    push_up(u);
}
Matrix query(int u, int ql, int qr, int l, int r) {
    if (ql <= l && qr >= r) return sum[u][0];
    int mid = (l + r) >> 1;
    push_down(u);
    Matrix ret;
    ret.a[0][0] = 1;
    ret.a[0][1] = 0;
    ret.a[1][0] = 0;
    ret.a[1][1] = 1;
    if (ql <= mid) ret = ret * query(u<<1, ql, qr, l, mid);
    if (qr > mid) ret = ret * query(u<<1|1, ql, qr, mid+1, r);
    return ret;
}

void solve() {
    int n, m; cin >> n >> m;
    cin >> s;
    init();
    build(1, 1, n);
    for (int i = 1; i <= m; i++) {
        int opt, x, y; cin >> opt >> x >> y;
        if (opt == 1) modify(1, x, y, 1, n);
        else {
            int a, b; cin >> a >> b;
            Matrix ret = query(1, x, y, 1, n), ans;
            ans.a[0][0] = a;
            ans.a[0][1] = b;
            ans = ans * ret;
            printf("%lld %lld\n", ans.a[0][0], ans.a[0][1]);
        }
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值