Codeforces - 498D. Traffic Jams in the Land - 线段树+数学

Traffic Jams in the Land

题目链接

分类dp number theory data structures

1.题意概述

  • 某个国家有 (n+1) 个城市 (1n105) ,城市之间有高速公路,其中第 i 段高速公路是从城市 i 通往城市 (i+1) 的,而且第 i 条道路有一个属性值 ai(2ai6) 表示这段城市的拥堵状态,当我们要从城市 x 到城市 y 时候,定义时刻 t 从0开始,如果当前时刻 t ax 的倍数,那么当前车辆就不能行驶,只能停在原地,等待时间飞逝,否则行驶的速度是 1ai 。现在有两类操作, q(1q105) 次查询:
    • 1 x y查询从城市x到城市y所需要耗费的时间;
    • 2 x y修改第x个城市的拥堵值 ax y

2.解题思路

  • 注意到 2ai6 ,那么实际上时间状态最多只有60种(是区间 [2,6] 的最小公倍数),区间问题,我们可以用线段树维护延时延时,因为有60种状态,因此我们要开60颗线段树,查洵时候按要求。
  • 一个大trick:因为线段树至少4倍,内存,还要乘以60倍,因此特别要注意内存限制。我以前的板还对每个节点存了左端点和右端点,无形之中增加了两倍内存,容易Memory Limited Ecxeed

3.AC代码

class SegmentTree {
public:
#define lson (root << 1)
#define rson (root << 1 | 1)
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
    int t[maxn << 2][N];

    void pushup(int root) {
        rep(i, 0, N) {
            int x = (i + t[lson][i]) % N;
            t[root][i] = t[lson][i] + t[rson][x];
        }
    }

    void build(int l, int r, int root) {
        if (l == r) {
            int x;
            scanf("%d", &x);
            rep(i, 0, N) t[root][i] = (i % x) ? 1 : 2;
            return;
        }
        int mid = l + r >> 1;
        build(l, mid, lson);
        build(mid + 1, r, rson);
        pushup(root);
    }

    void update(int a, int b, int l, int r, int val, int root) {
        if (l <= a && b <= r) {
            rep(i, 0, N) t[root][i] = (i % val) ? 1 : 2;
            return;
        }
        int mid = a + b >> 1;
        if (l <= mid) update(a, mid, l, r, val, lson);
        if (r > mid) update(mid + 1, b, l, r, val, rson);
        pushup(root);
    }

    int query(int a, int b, int l, int r, int x, int root) {
        if (l <= a && b <= r)
            return x + t[root][x % N];
        int mid = a + b >> 1;
        if (l <= mid) x = query(a, mid, l, r, x, lson);
        if (r > mid) x = query(mid + 1, b, l, r, x, rson);
        return x;
    }
#undef lenr
#undef lenl
#undef lent
#undef rson
#undef lson
} T;
inline void solve() {
    int n, q;
    scanf("%d", &n);
    T.build(1, n, 1);
    scanf("%d", &q);
    while (q--) {
        char op[2];
        int x, y;
        scanf("%s%d%d", op, &x, &y);
        if (op[0] == 'C') T.update(1, n, x, x, y, 1);
        else printf("%d\n", T.query(1, n, x, y - 1, 0, 1));
    }
}

你可能感兴趣的:(线段树及其应用,数学,Codeforces)