20250819

T1

集合查询

\(x | \gcd(v, k) \longleftrightarrow x | v \land x | k\),对每个数维护一棵 01trie,加入一个数时加入其所有因数的 01trie 即可。要求和不超过的限制是容易的,每次要进入 trie 的一棵子树时判断子树 \(\max\) 是否超过限制即可。

代码
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int q;
vector<int> vec[100005];
int rt[100005], ncnt;
int son[20000005][2];
int mn[20000005];
void Insert(int x, int y) {
    int p = rt[x];
    if (!p) p = rt[x] = ++ncnt;
    mn[p] = min(mn[p], y);
    for (int i = 18; ~i; i--) {
        int t = ((y >> i) & 1);
        if (!son[p][t]) son[p][t] = ++ncnt;
        p = son[p][t];
        mn[p] = min(mn[p], y);
    }
}
int Query(int p, int x, int s) {
    int y = 0;
    for (int i = 18; ~i; i--) {
        int t = (!((x >> i) & 1));
        if (son[p][t] && x + mn[son[p][t]] <= s) y |= (t << i), p = son[p][t];
        else y |= ((!t) << i), p = son[p][!t];
    }
    return y;
}
bool vis[100005];
int main() {
    freopen("set.in", "r", stdin);
    freopen("set.out", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    memset(mn, 63, sizeof mn);
    for (int i = 1; i <= 100000; i++) {
        for (int j = i; j <= 100000; j += i) 
            vec[j].emplace_back(i);
    }
    cin >> q;
    while (q--) {
        int op, x, y, z;
        cin >> op >> x;
        if (op == 1) {
            if (vis[x]) continue;
            vis[x] = 1;
            for (int v : vec[x]) Insert(v, x);
        } else {
            cin >> y >> z;
            if (mn[rt[y]] + x > z || x % y != 0) { cout << "-1\n"; continue; }
            cout << Query(rt[y], x, z) << "\n";
        }
    }
    return 0;
}

T2

公交路线

每次跳到能跳到的最高的位置,直到将要跳过 LCA。然后查询是否存在一条线路两端分别位于当前两个点的子树中即可。前面的可以树上倍增,后面的直接二维数点。可能需要判掉询问点有祖先后代关系的情况。

代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <array>
#define lowbit(x) ((x) & (-(x)))
using namespace std;
const int inf = 0x3f3f3f3f;
inline void Cmin(int &x, int y) { x = min(x, y); }
int n, m, K;
int head[100005], nxt[200005], to[200005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int top[100005], son[100005], dep[100005], sz[100005], f[100005];
int L[100005], R[100005], ncnt;
int _dfn[100005];
int F[100005][20];
void dfs1(int x, int fa, int d) {
    dep[x] = d;
    f[x] = fa;
    sz[x] = 1;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != fa) {
            dfs1(v, x, d + 1);
            sz[x] += sz[v];
            if (sz[v] > sz[son[x]]) 
                son[x] = v;
        }
    }
}
void dfs2(int x, int t) {
    top[x] = t;
    _dfn[L[x] = ++ncnt] = x;
    if (son[x]) dfs2(son[x], t);
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != f[x] && v != son[x]) 
            dfs2(v, v);
    }
    R[x] = ncnt;
}
int LCA(int x, int y) {
    while (top[x] ^ top[y]) (dep[top[x]] < dep[top[y]]) ? (y = f[top[y]]) : (x = f[top[x]]);
    return (dep[x] < dep[y] ? x : y);
}
int up[100005], stk[100005];
array<int, 3> ln[100005];
void dfs3(int x) {
    stk[dep[x]] = x;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != f[x]) {
            dfs3(v);
            Cmin(up[x], up[v]);
        }
    }
    F[x][0] = stk[up[x]];
}
void dfs4(int x) {
    for (int i = 1; i < 20; i++) F[x][i] = F[F[x][i - 1]][i - 1];
    for (int i = head[x]; i; i = nxt[i]) { int v = to[i]; if (v != f[x]) dfs4(v); }
}
int s[100005], t[100005];
struct Query {
    int x, y, id, v;
} qs[500005];
int qcnt;
int tmp[100005];
struct BIT {
    int bit[100005];
    void add(int x, int y) { for (; x <= 100000; x += lowbit(x)) bit[x] += y; }
    int query(int x) {
        int ret = 0;
        for (; x; x -= lowbit(x)) ret += bit[x];
        return ret;
    }
} bit;
int ans[100005];
int goUp(int &x, int y) {
    if (dep[F[x][19]] > dep[y]) return inf;
    int cnt = 0;
    for (int i = 19; ~i; i--) if (dep[F[x][i]] > dep[y]) x = F[x][i], cnt += (1 << i);
    return cnt + 1;
}
int main() {
    freopen("bus.in", "r", stdin);
    freopen("bus.out", "w", stdout);
    cin >> n >> m >> K;
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
    }
    dfs1(1, 0, 1);
    dfs2(1, 1);
    for (int i = 1; i <= n; i++) up[i] = dep[i];
    for (int i = 1; i <= m; i++) {
        cin >> ln[i][0] >> ln[i][1];
        if (L[ln[i][0]] > L[ln[i][1]]) swap(ln[i][0], ln[i][1]);
        ln[i][2] = LCA(ln[i][0], ln[i][1]);
        Cmin(up[ln[i][0]], dep[ln[i][2]]);
        Cmin(up[ln[i][1]], dep[ln[i][2]]);
        qs[++qcnt] = (Query) { L[ln[i][0]], L[ln[i][1]], -1, 1 };
    }
    dfs3(1);
    dfs4(1);
    for (int i = 1; i <= K; i++) {
        cin >> s[i] >> t[i];
        (dep[s[i]] < dep[t[i]]) ? void() : swap(s[i], t[i]);
        if (L[s[i]] <= L[t[i]] && L[t[i]] <= R[s[i]]) ans[i] = goUp(t[i], s[i]);
        else {
            int z = LCA(s[i], t[i]);
            ans[i] = goUp(s[i], z) + goUp(t[i], z);
            if (L[s[i]] > L[t[i]]) swap(s[i], t[i]);
            qs[++qcnt] = (Query) { L[s[i]] - 1, L[t[i]] - 1, i, 1 };
            qs[++qcnt] = (Query) { R[s[i]], L[t[i]] - 1, i, -1 };
            qs[++qcnt] = (Query) { L[s[i]] - 1, R[t[i]], i, -1 };
            qs[++qcnt] = (Query) { R[s[i]], R[t[i]], i, 1 };
        }
    }
    sort(qs + 1, qs + qcnt + 1, [](Query x, Query y) { return x.x == y.x ? (x.y == y.y ? (x.id < y.id) : (x.y < y.y)) : (x.x < y.x); });
    for (int i = 1; i <= qcnt; i++) {
        if (qs[i].id < 0) bit.add(qs[i].y, 1);
        else tmp[qs[i].id] += qs[i].v * bit.query(qs[i].y);
    }
    for (int i = 1; i <= K; i++) {
        if (ans[i] >= inf - 1) cout << "-1\n";
        else cout << ans[i] - (tmp[i] != 0) - 1 << "\n";
    }
    return 0;
}

T3

游戏

先求出每条边上剩下的堆异或和为每个数的概率,然后跑一遍矩阵树即可。可以先 fwt 然后扔进矩阵树最后再 ifwt,这样中途就不用来回变了。接下来要求出剩下的异或和为每个数的概率,实际上是要把一车形如 \(\frac{3}{4}x^{\varnothing} + \frac{1}{4}x^{S}\) 的东西卷起来。观察卷完之后的 fwt 数组,发现只会有 \(1\)\(\frac{1}{2}\) 两种值,由异或 fwt 的定义容易发现,且 \(\frac{1}{2}\) 只会在 \(x^{T}(|T \cap S| \equiv 1 \bmod 2)\) 的情况下出现。因此只需要求有多少数和当前位置指数上的集合交大小为奇数。我们考虑对计数数组进行 fwt,这样每个位置上的数就是偶数 - 奇数,而偶数 + 奇数就是所有数的总数。把两个减了除以二就可以算出奇数的个数。于是就做完了。

代码
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
#define int long long
using namespace std;
const int P = 998244353, i2 = (P + 1) / 2, i4 = i2 * i2 % P;
inline void Madd(int &x, int y) { (x += y) >= P ? (x -= P) : 0; }
inline int Msum(int x, int y) { return Madd(x, y), x; }
inline int qpow(int x, int y = P - 2) {
    int ret = 1;
    while (y) {
        if (y & 1) ret = ret * x % P;
        y >>= 1; x = x * x % P;
    }
    return ret;
}
int n, m;
struct poly {
    vector<int> vec;
    int& operator[](int x) { return vec[x]; }
    poly() { vec.resize(1 << 10); }
    void operator+=(poly &b) { for (int i = 0; i < (1 << m); i++) Madd(vec[i], b[i]); }
    void operator-=(poly b) { for (int i = 0; i < (1 << m); i++) Madd(vec[i], P - b[i]); }
    void operator*=(poly &b) { for (int i = 0; i < (1 << m); i++) vec[i] = vec[i] * b[i] % P; }
    poly operator~() { poly ret; for (int i = 0; i < (1 << m); i++) ret[i] = qpow(vec[i]); return ret; }
    bool _0() { return *max_element(vec.begin(), vec.begin() + (1 << m)) == 0; }
} A[75][75];
inline poly operator*(poly a, poly &b) { return a *= b, a; }
void FWT(poly &f, int t = 1) {
    for (int i = 1; i < (1 << m); i <<= 1) {
        for (int j = 0; j < (1 << m); j += (i << 1)) {
            for (int k = 0; k < i; k++) {
                int x = f[j | k], y = f[i | j | k];
                if (t == 1) {
                    f[j | k] = Msum(x, y);
                    f[i | j | k] = Msum(x, P - y);
                } else {
                    f[j | k] = Msum(x, y) * i2 % P;
                    f[i | j | k] = Msum(x, P - y) * i2 % P;
                }
            }
        }
    }
}
poly detp(int N) {
    int rc = 1;
    for (int i = 1; i < N; i++) {
        if (A[i][i]._0()) {
            for (int j = i; j < N; j++) {
                if (!A[j][i]._0()) {
                    rc = P - rc;
                    swap(A[i], A[j]);
                    break;
                }
            }
        }
        poly coe = ~A[i][i];
        for (int j = i + 1; j < N; j++) {
            if (!A[j][i]._0()) {
                for (int k = N - 1; k >= i; k--) 
                    A[j][k] -= A[i][k] * coe * A[j][i];
            }
        }
    }
    poly ret;
    for (int i = 0; i < (1 << m); i++) ret[i] = rc;
    for (int i = 1; i < N; i++) ret *= A[i][i];
    return ret;
}
int iA[75][75];
int deti(int N) {
    int ret = 1;
    for (int i = 1; i < N; i++) {
        if (iA[i][i] == 0) {
            for (int j = i; j < N; j++) {
                if (iA[j][i]) {
                    ret = P - ret;
                    swap(iA[i], iA[j]);
                    break;
                }
            }
        }
        int coe = qpow(iA[i][i]);
        for (int j = 1; j < N; j++) {
            if (i != j && iA[j][i]) {
                for (int k = N; k >= i; k--) 
                    Madd(iA[j][k],  P - iA[i][k] * coe % P * iA[j][i] % P);
            }
        }
    }
    for (int i = 1; i < N; i++) ret = ret * iA[i][i] % P;
    return ret;
}
signed main() {
    freopen("gemo.in", "r", stdin);
    freopen("gemo.out", "w", stdout);
    cin >> n >> m;
    for(int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            int K, tk, x; cin >> K; tk = K;
            if (K) {
                poly tmp0;
                while (K--) cin >> x, ++tmp0[x];
                FWT(tmp0);
                for (int k = 0; k < (1 << m); k++) tmp0[k] = qpow(i2, (tk + P - tmp0[k]) * i2 % P);
                Madd(iA[i][j], P - 1), Madd(iA[j][i], P - 1);
                ++iA[i][i], ++iA[j][j];
                A[i][j] -= tmp0, A[j][i] -= tmp0;
                A[i][i] += tmp0, A[j][j] += tmp0;
            }
        }
    }
    poly res = detp(n);
    int ret = deti(n);
    FWT(res, -1);
    cout << (P + 1 - res[0] * qpow(ret) % P) % P << "\n";
    return 0;
}

T4

音符大师

考虑一个朴素的 dp:\(f_{i, j, k}\) 表示当前打完了第 \(i\) 个,一个手在 \(j\),另一个在 \(k\) 的最小代价。容易发现 \(j,k\) 至少一个 \(=i\),于是把那两维合并,剩下一维记不在 \(i\) 的那只手在哪。显然如果下一个音符落在当前手的覆盖范围内,那肯定不会动的。于是第一维只需要记 \(0 / 1\) 表示当前在 \(p_i\) 还是 \(p_i - L\)。另一维也是同理,只需要记 \(2n\) 个位置。线段树维护,每次转移分类讨论:下一个音符拿当前在 \(i\) 的手打,那么找到下一个不在 \([p_i, p_i + L]\) 的音符 \(x\)(找不到直接更新答案),把当前线段树打个全局加 tag 合并过去即可。若下一个音符拿另一个手打,那么还是考虑 \(x\) 能否被另一个手打到,如果不能,就把当前的 \(f_{i, j}\) 更新到 \(f_{x, i}\) 上去(注意 \(i\) 从第一维 变成了第二维,因为它变成“另一只手”了);如果能打到,那么这样的 \(j\) 只有至多 \(L\) 个,再找到第一个不被两个手包含的音符,考虑这个音符要拿哪个手打,分别做单点更新即可。总时间复杂度 \(\mathcal{O}(nL\log n)\)。不知道出于什么心理要卡正解常。

代码
#pragma GCC optimize("Ofast,inline,unroll-loops")
#include <iostream>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int _inf = 0x3f3f3f3f;
inline void Cmin(long long &x, long long y) { x = min(x, y); }
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++
char buf[1<<21], *p1, *p2, ch;
long long read() {
    long long ret = 0, neg = 0; char c = getchar(); neg = (c == '-');
    while (c < '0' || c > '9') c = getchar(), neg |= (c == '-');
    while (c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
    return ret * (neg ? -1 : 1);
}
int n, m;
long long ans = inf;
int a[50005], d1[50005], dcnt1;
int d2[100005], dcnt2;
int rt[50005];
struct Persistent_Segment_Tree {
    struct node { int l, r, mn; } T[1500005];
    int ncnt;
    void Insert(int &p, int q, int l, int r, int x, int y) {
        T[p = ++ncnt] = T[q];
        T[p].mn = y;
        if (l == r) return;
        int mid = (l + r) >> 1;
        if (x <= mid) Insert(T[p].l, T[q].l, l, mid, x, y);
        else Insert(T[p].r, T[q].r, mid + 1, r, x, y);
    }
    int Query(int o, int l, int r, int L, int R) {
        if (L > R || !o) return _inf;
        if (L <= l && r <= R) return T[o].mn;
        int mid = (l + r) >> 1;
        if (R <= mid) return Query(T[o].l, l, mid, L, R);
        if (L > mid) return Query(T[o].r, mid + 1, r, L, R);
        return min(Query(T[o].l, l, mid, L, R), Query(T[o].r, mid + 1, r, L, R));
    }
} pseg;
struct Segment_Tree {
    struct node {
        int l, r;
        long long tg, mn1, mn2;
    } T[7000005];
    int ncnt;
    inline void tag(int o, long long v) { T[o].tg += v, T[o].mn1 += v, T[o].mn2 += v; }
    inline void pushup(int o) { T[o].mn1 = min(T[T[o].l].mn1, T[T[o].r].mn1), T[o].mn2 = min(T[T[o].l].mn2, T[T[o].r].mn2); }
    void pushdown(int o) {
        if (!T[o].tg) return;
        T[o].l ? tag(T[o].l, T[o].tg) : void();
        T[o].r ? tag(T[o].r, T[o].tg) : void();
        T[o].tg = 0;
    }
    void Insert(int &o, int l, int r, int x, long long y) {
        if (!o) T[o = ++ncnt] = (node) { 0, 0, 0, inf, inf };
        if (l == r) {
            T[o].mn1 = min(T[o].mn1, y - d2[x]);
            T[o].mn2 = min(T[o].mn2, y + d2[x]);
            return;
        }
        pushdown(o);
        int mid = (l + r) >> 1;
        if (x <= mid) Insert(T[o].l, l, mid, x, y);
        else Insert(T[o].r, mid + 1, r, x, y);
        pushup(o);
    }
    int Merge(int p, int q, int l, int r) {
        if (!p || !q) return p | q;
        if (l == r) {
            T[p].mn1 = min(T[p].mn1, T[q].mn1), T[p].mn2 = min(T[p].mn2, T[q].mn2);
            return p;
        }
        pushdown(p), pushdown(q);
        int mid = (l + r) >> 1;
        T[p].l = Merge(T[p].l, T[q].l, l, mid);
        T[p].r = Merge(T[p].r, T[q].r, mid + 1, r);
        pushup(p);
        return p;
    }
    long long Query1(int o, int l, int r, int L, int R) {
        if (!o) return inf;
        if (L <= l && r <= R) return T[o].mn1;
        int mid = (l + r) >> 1;
        pushdown(o);
        if (R <= mid) return Query1(T[o].l, l, mid, L, R);
        if (L > mid) return Query1(T[o].r, mid + 1, r, L, R);
        return min(Query1(T[o].l, l, mid, L, R), Query1(T[o].r, mid + 1, r, L, R));
    }
    long long Query2(int o, int l, int r, int L, int R) {
        if (!o) return inf;
        if (L <= l && r <= R) return T[o].mn2;
        int mid = (l + r) >> 1;
        pushdown(o);
        if (R <= mid) return Query2(T[o].l, l, mid, L, R);
        if (L > mid) return Query2(T[o].r, mid + 1, r, L, R);
        return min(Query2(T[o].l, l, mid, L, R), Query2(T[o].r, mid + 1, r, L, R));
    }
    void get(int o, int l, int r, int L, int R, vector<pair<int, long long> > &vec) {
        if (!o) return;
        if (l == r) return vec.emplace_back(l, T[o].mn2), void();
        int mid = (l + r) >> 1;
        pushdown(o);
        if (R <= mid) return get(T[o].l, l, mid, L, R, vec);
        if (L > mid) return get(T[o].r, mid + 1, r, L, R, vec);
        return get(T[o].l, l, mid, L, R, vec), get(T[o].r, mid + 1, r, L, R, vec);
    }
} seg;
int rt2[50005][2];
long long mn[50005][2];
signed main() {
    seg.T[0] = (Segment_Tree::node) { 0, 0, 0, inf, inf };
    freopen("music.in", "r", stdin);
    freopen("music.out", "w", stdout);
    memset(mn, 63, sizeof mn);
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = read(), d1[i] = a[i], d2[++dcnt2] = a[i], d2[++dcnt2] = a[i] - m;
    d1[dcnt1 = n + 1] = 0; d2[++dcnt2] = 0; d2[++dcnt2] = -m;
    sort(d1 + 1, d1 + dcnt1 + 1);
    sort(d2 + 1, d2 + dcnt2 + 1);
    dcnt1 = unique(d1 + 1, d1 + dcnt1 + 1) - d1 - 1;
    dcnt2 = unique(d2 + 1, d2 + dcnt2 + 1) - d2 - 1;
    for (int i = n; i; i--) {
        int x = lower_bound(d1 + 1, d1 + dcnt1 + 1, a[i]) - d1;
        pseg.Insert(rt[i], rt[i + 1], 1, dcnt1, x, i);
    }
    #define _l1(x) lower_bound(d1 + 1, d1 + dcnt1 + 1, x) - d1
    #define _u1(x) upper_bound(d1 + 1, d1 + dcnt1 + 1, x) - d1
    #define _l2(x) lower_bound(d2 + 1, d2 + dcnt2 + 1, x) - d2
    #define _u2(x) upper_bound(d2 + 1, d2 + dcnt2 + 1, x) - d2
    seg.Insert(rt2[0][0], 1, dcnt2, _l2(0), 0);
    mn[0][0] = 0;
    for (int i = 0; i <= n; i++) for (int _ : { 0, 1 }) {
        int tl = a[i] - _ * m, tr = a[i] + (!_) * m, x = _l2(tl), t1 = _l1(tl), t2 = _u1(tr), y = min(pseg.Query(rt[i + 1], 1, dcnt1, 1, t1 - 1), pseg.Query(rt[i + 1], 1, dcnt1, t2, dcnt1));
        int v1 = pseg.Query(rt[i + 1], 1, dcnt1, 1, t1 - 1), v2 = pseg.Query(rt[i + 1], 1, dcnt1, t2, dcnt1);
        long long tmp;
        if (y >= _inf) { Cmin(ans, mn[i][_]); continue; }
        tmp = seg.Query2(rt2[i][_], 1, dcnt2, _u2(a[y]), dcnt2) - a[y];
        seg.Insert(rt2[y][0], 1, dcnt2, x, tmp); Cmin(mn[y][0], tmp);
        tmp = a[y] - m + seg.Query1(rt2[i][_], 1, dcnt2, 1, _l2(a[y] - m) - 1);
        seg.Insert(rt2[y][1], 1, dcnt2, x, tmp); Cmin(mn[y][1], tmp);
        if (a[y] < tl) {
            vector<pair<int, long long> > vec;
            seg.get(rt2[i][_], 1, dcnt2, _l2(a[y] - m), _u2(a[y]) - 1, vec);
            for (auto p : vec) {
                int t = p.first, u = d2[t];
                long long val = p.second;
                if (val >= inf) continue;
                int z = min({ pseg.Query(rt[i + 1], 1, dcnt1, 1, _l1(u) - 1), pseg.Query(rt[i + 1], 1, dcnt1, _u1(u + m), t1 - 1), v2 });
                if (z >= _inf) { Cmin(ans, val - u); continue; }
                if (a[z] < tl) seg.Insert(rt2[z][0], 1, dcnt2, t, tmp = val - u + tl - a[z]), Cmin(mn[z][0], tmp);
                else seg.Insert(rt2[z][1], 1, dcnt2, t, tmp = val - u + a[z] - m - tl), Cmin(mn[z][1], tmp);
                if (a[z] < u) seg.Insert(rt2[z][0], 1, dcnt2, x, tmp = val - a[z]), Cmin(mn[z][0], tmp);
                else seg.Insert(rt2[z][1], 1, dcnt2, x, tmp = val - u - u + a[z] - m), Cmin(mn[z][1], tmp);
            }
            seg.tag(rt2[i][_], tl - a[y]);
            rt2[y][0] = seg.Merge(rt2[y][0], rt2[i][_], 1, dcnt2);
            Cmin(mn[y][0], mn[i][_] + tl - a[y]);
        } else {
            vector<pair<int, long long> > vec;
            seg.get(rt2[i][_], 1, dcnt2, _l2(a[y] - m), _u2(a[y]) - 1, vec);
            for (auto p : vec) {
                int t = p.first, u = d2[t];
                long long val = p.second;
                if (val >= inf) continue;
                int z = min({ v1, pseg.Query(rt[i + 1], 1, dcnt1, t2, _l1(u) - 1), pseg.Query(rt[i + 1], 1, dcnt1, _u1(u + m), dcnt1) });
                if (z >= _inf) { Cmin(ans, val - u); continue; }
                if (a[z] < tl) seg.Insert(rt2[z][0], 1, dcnt2, t, tmp = val - u + tl - a[z]), Cmin(mn[z][0], tmp);
                else seg.Insert(rt2[z][1], 1, dcnt2, t, tmp = val - u + a[z] - m - tl), Cmin(mn[z][1], tmp);
                if (a[z] < u) seg.Insert(rt2[z][0], 1, dcnt2, x, tmp = val - a[z]), Cmin(mn[z][0], tmp);
                else seg.Insert(rt2[z][1], 1, dcnt2, x, tmp = val - u - u + a[z] - m), Cmin(mn[z][1], tmp);
            }
            seg.tag(rt2[i][_], a[y] - tl - m);
            rt2[y][1] = seg.Merge(rt2[y][1], rt2[i][_], 1, dcnt2);
            Cmin(mn[y][1], mn[i][_] + a[y] - tl - m);
        }
    }
    cout << ans << "\n";
    return 0;
}

T3 经典套路。T4 经典另一维线段树维护 dp。来回更新。

posted @ 2025-08-25 12:21  forgotmyhandle  阅读(4)  评论(0)    收藏  举报