20250822

T1

帝国重建

没懂。不求甚解。

代码
#include <iostream>
#define int long long
using namespace std;
int n;
int a[1000005];
pair<int, int> f[1000005], g[1000005];
signed main() {
    freopen("empire.in", "r", stdin);
    freopen("empire.out", "w", stdout);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i], a[i] += a[i - 1], g[i] = max(g[i], make_pair(0ll, 0ll));
    for (int i = 1; i <= n; i++) {
        g[i] = max(g[i], g[i - 1]);
        f[i] = g[i], ++f[i].first;
        int l = i + 1, r = n, mid, t = i - 1;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (a[mid] - a[i] >= a[i] - a[f[i].second]) t = mid, r = mid - 1;
            else l = mid + 1;
        }
        f[i].second = i;
        g[t] = max(g[t], f[i]);
    }
    cout << n - f[n].first << "\n";
    return 0;
}

T2

树上铲雪

没懂。不求甚解。

代码
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
int n;
int a[200005], f[200005];
int head[200005], nxt[400005], to[400005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int ans;
void dfs(int x, int fa) {
    int s = 0, t = 0;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != fa) {
            dfs(v, x);
            s += f[v];
            t = max(t, f[v]);
        }
    }
    t = min(s - t, s >> 1);
    if (a[x] >= s) f[x] = a[x];
    else {
        int v = min({ t, a[x], s - a[x] });
        ans += v;
        f[x] = a[x] - v;
        if (s - a[x] > v) ans += s - v * 2 - a[x] + v;
    }
}
signed main() {
    freopen("snow.in", "r", stdin);
    freopen("snow.out", "w", stdout);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
    }
    dfs(1, 0);
    cout << ans + f[1] << "\n";
    return 0;
}

T3

风铃

链直接线段树,环把最小点放开头,容斥考虑钦定最后一个和第一个相同,要求中间的合法方案数,发现就是第一个到倒数第二个这些构成合法环的方案数。再容斥,然后直接递推即可。

代码
#include <iostream>
#define int long long
using namespace std;
const int P = 998244353, N = 200001;
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; }
struct Segment_Tree {
    int s[800005], len[800005], atag[800005], mtag[800005];
    inline void taga(int o, int v) { Madd(s[o], len[o] * v % P), Madd(atag[o], v); }
    inline void tagm(int o, int v) { mtag[o] = mtag[o] * v % P, atag[o] = atag[o] * v % P, s[o] = s[o] * v % P; }
    inline void pushdown(int o) {
        if (mtag[o] != 1) {
            tagm(o << 1, mtag[o]);
            tagm(o << 1 | 1, mtag[o]);
        }
        if (atag[o] != 0) {
            taga(o << 1, atag[o]);
            taga(o << 1 | 1, atag[o]);
        }
        mtag[o] = 1, atag[o] = 0;
    }
    void Build(int o, int l, int r) {
        mtag[o] = 1;
        len[o] = r - l + 1;
        if (l == r) 
            return;
        int mid = (l + r) >> 1;
        Build(o << 1, l, mid);
        Build(o << 1 | 1, mid + 1, r);
    }
    void Add(int o, int l, int r, int L, int R, int v) {
        if (L <= l && r <= R) 
            return taga(o, v);
        pushdown(o);
        int mid = (l + r) >> 1;
        if (L <= mid) 
            Add(o << 1, l, mid, L, R, v);
        if (R > mid) 
            Add(o << 1 | 1, mid + 1, r, L, R, v);
        s[o] = Msum(s[o << 1], s[o << 1 | 1]);
    }
    void Mul(int o, int l, int r, int L, int R, int v) {
        if (L <= l && r <= R) 
            return tagm(o, v);
        pushdown(o);
        int mid = (l + r) >> 1;
        if (L <= mid) 
            Mul(o << 1, l, mid, L, R, v);
        if (R > mid) 
            Mul(o << 1 | 1, mid + 1, r, L, R, v);
        s[o] = Msum(s[o << 1], s[o << 1 | 1]);
    }
    int Query(int o, int l, int r, int L, int R) {
        if (L <= l && r <= R) 
            return s[o];
        pushdown(o);
        int mid = (l + r) >> 1;
        if (R <= mid) 
            return Query(o << 1, l, mid, L, R);
        if (L > mid) 
            return Query(o << 1 | 1, mid + 1, r, L, R);
        return Msum(Query(o << 1, l, mid, L, R), Query(o << 1 | 1, mid + 1, r, L, R));
    }
} seg;
int n, m;
int head[200005], nxt[400005], to[400005], ecnt;
int deg[200005], a[200005];
bool vis[200005];
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int stk[200005], sz;
void dfs(int x) {
    if (vis[x]) return;
    vis[x] = 1;
    stk[++sz] = a[x];
    for (int i = head[x]; i; i = nxt[i]) dfs(to[i]);
}
int f[200005];
signed main() {
    freopen("rainbow.in", "r", stdin);
    freopen("rainbow.out", "w", stdout);
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
        ++deg[u], ++deg[v];
    }
    seg.Build(1, 1, N);
    int ans = 1;
    for (int i = 1; i <= n; i++) {
        if (!deg[i]) vis[i] = 1, ans = ans * a[i] % P;
        if (deg[i] == 1 && !vis[i]) {
            sz = 0, dfs(i);
            seg.Mul(1, 1, N, 1, N, 0);
            seg.Add(1, 1, N, 1, stk[1], 1);
            for (int j = 2; j <= sz; j++) {
                int s = seg.s[1];
                seg.Mul(1, 1, N, 1, N, P - 1);
                seg.Add(1, 1, N, 1, N, s);
                seg.Mul(1, 1, N, stk[j] + 1, N, 0);
            }
            ans = ans * seg.s[1] % P;
        }
    }
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            sz = 0, dfs(i);
            int mp = 1;
            for (int j = 1; j <= sz; j++) stk[j] < stk[mp] ? (mp = j) : 0;
            seg.Mul(1, 1, N, 1, N, 0);
            seg.Add(1, 1, N, 1, stk[mp], 1);
            f[mp] = 0;
            for (int j = mp % sz + 1; j != mp; j = j % sz + 1) {
                int s = seg.s[1];
                seg.Mul(1, 1, N, 1, N, P - 1);
                seg.Add(1, 1, N, 1, N, s);
                seg.Mul(1, 1, N, stk[j] + 1, N, 0);
                f[j] = Msum(seg.s[1], P - f[j == 1 ? sz : j - 1]);
            }
            ans = ans * f[mp == 1 ? sz : mp - 1] % P;
        }
    }
    cout << ans << "\n";
    return 0;
}

T4

拯救

边按删除时间建 kruskal 重构树,每个点相当于 kruskal 上的一段直链,行动路径也是从一个点开始的到叶子的链。\(c = 0\) 就是要求从指定点往下的这条链最多经过多少给出的链。这是容易求的,将贡献分为完全在子树内的和覆盖自己的即可。接下来考虑 \(c \neq 0\),容易发现回溯一定回溯到最顶上的点,那么相当于从两个给定起点出发,经过的链的并最多多少。这有两种情况,一种是走的两条路径在子树中分叉,一种是上面的下来的时候走一半跑路了,没走到下面的起点。第一种把贡献分三类计算,一类是完全在分叉点子树内的,一种是分叉点到上面的起点之间的,一种是覆盖上面的起点的。都是容易统计的。第二种枚举上面往下走到哪个点跑路了,贡献分四类:一类是完全在下面起点子树内的,一种是跑路点到下面的起点这些点开始的且覆盖下面的起点的,一类是在上面的起点到跑路点出发的,一类是覆盖上面起点的。由于 \(c \ge 24\),第二类可以直接暴力维护,其他的都是容易维护的。需要注意的是对于一个询问的起点 \(x\),以其为终点的路径的结束时间可能会早于 \(x\) 的询问时间,这个时候这条路径不能贡献 \(x\),需要把它干掉。离线按询问时间排序即可。总复杂度大概单 \(\log\)\(nc\) 吧。反正轻松跑过。

代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++
char buf[1<<21], *p1, *p2, ch;
int read() {
    int 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, K, C;
struct Edge {
    int u, v, t;
} e[500005];
int f[1000005], dt[1000005];
int dsu[1000005], ncnt;
int st[500005], ed[500005];
int getf(int x) { return (dsu[x] == x ? x : (dsu[x] = getf(dsu[x]))); }
int ls[1000005], rs[1000005];
int stk[1000005], dep[1000005];
int dfn[1000005], *L = dfn, R[1000005], dfncnt;
int pre[1000005], mx[1000005], cv[1000005];
vector<int> vec[1000005];
vector<pair<int, int> > qx[1000005];
int val[1000005], Qx[500005], Qy[500005], Qz[500005];
int cnt[1000005][26];
int xp[500005], xq[500005];
void dfs1(int x) {
    dfn[x] = ++dfncnt;
    dep[x] = dep[f[x]] + 1;
    stk[dep[x]] = x;
    if (x <= n) {
        int l, r, mid, p, q;
        if (st[x]) {
            l = 1, r = dep[x], p = dep[x], q = dep[x];
            while (l <= r) {
                mid = (l + r) >> 1;
                if (dt[f[stk[mid]]] <= st[x]) p = stk[mid], l = mid + 1;
                else r = mid - 1;
            }
            l = 1, r = dep[x];
            while (l <= r) {
                mid = (l + r) >> 1;
                if (dt[f[stk[mid]]] <= ed[x]) q = stk[mid], l = mid + 1;
                else r = mid - 1;
            }
            ++cv[q], --cv[f[p]];
            vec[p].emplace_back(q);
            xp[x] = p, xq[x] = q;
        }
        for (auto v : qx[x]) {
            l = 1, r = dep[x], Qx[v.first] = x;
            while (l <= r) {
                mid = (l + r) >> 1;
                if (dt[stk[mid]] > v.second - 1) Qx[v.first] = stk[mid], r = mid - 1;
                else l = mid + 1;
            }
            l = 1, r = dep[x], Qz[v.first] = x;
            while (l <= r) {
                mid = (l + r) >> 1;
                if (dt[stk[mid]] > max(1, v.second - C) - 1) Qz[v.first] = stk[mid], r = mid - 1;
                else l = mid + 1;
            }
        }
    } else dfs1(ls[x]), dfs1(rs[x]);
    R[x] = dfncnt;
}
void dfs2(int x) {
    stk[dep[x]] = x;
    pre[x] = pre[f[x]] + vec[x].size();
    val[x] = mx[x] = pre[x];
    for (int i = 1; i <= min(dep[x], C + 1); i++) {
        cnt[x][i] = cnt[x][i - 1];
        for (auto v : vec[stk[dep[x] - i + 1]]) cnt[x][i] += (L[x] <= dfn[v] && dfn[v] <= R[x]);
    }
    if (x <= n) return;
    dfs2(ls[x]), dfs2(rs[x]);
    mx[x] = max(mx[ls[x]], mx[rs[x]]);
    cv[x] += cv[ls[x]], cv[x] += cv[rs[x]];
    mx[ls[x]] -= pre[x], mx[rs[x]] -= pre[x];
    val[x] = max({ val[ls[x]], val[rs[x]], mx[ls[x]] + mx[rs[x]] + pre[x] });
}
int oq[500005], ox[500005];
int ans[500005];
void upd(int p, int q) { for (int i = dep[q] - dep[p] + 1; i <= C + 1; i++) --cnt[q][i]; }
int q;
int main() {
    freopen("save.in", "r", stdin);
    freopen("save.out", "w", stdout);
    ncnt = n = read(), m = read(), K = read(), q = read(), C = read();
    for (int i = 1; i <= m; i++) e[i].u = read(), e[i].v = read(), e[i].t = K + 1;
    for (int i = 1; i <= K; i++) {
        int op = read(), x = read();
        if (op == 1) e[x].t = i;
        else if (op == 2) st[x] = i;
        else ed[x] = i;
    }
    sort(e + 1, e + m + 1, [](Edge x, Edge y) { return x.t > y.t; });
    for (int i = 1; i <= n * 2; i++) dsu[i] = i;
    for (int i = 1; i <= n; i++) (ox[i] = i, dt[i] = K + 1), ((st[i] && !ed[i]) ? (ed[i] = K + 1) : 0);
    for (int i = 1; i <= m; i++) {
        int u = getf(e[i].u), v = getf(e[i].v);
        if (u != v) {
            f[u] = f[v] = dsu[u] = dsu[v] = ++ncnt;
            ls[ncnt] = u, rs[ncnt] = v;
            dt[ncnt] = e[i].t;
        }
    }
    for (int i = 1, x, y; i <= q; i++) {
        x = read(), y = read(), Qy[i] = y; oq[i] = i;
        qx[x].emplace_back(i, y);
    }
    dfs1(ncnt); dfs2(ncnt);
    sort(oq + 1, oq + q + 1, [](int x, int y) { return Qy[x] < Qy[y]; });
    sort(ox + 1, ox + n + 1, [](int x, int y) { return ed[x] < ed[y]; });
    for (int i = 1, j = 1, k = 1; i <= q; i++) {
        while (k <= n && ed[ox[k]] <= Qy[oq[i]] - C - 1) (st[ox[k]] ? --cv[xq[ox[k]]] : 0), ++k;
        while (j <= n && ed[ox[j]] <= Qy[oq[i]] - 1) (st[ox[j]] ? upd(xp[ox[j]], xq[ox[j]]) : void()), ++j;
        int x = Qx[oq[i]], z = Qz[oq[i]];
        ans[oq[i]] = val[x] - pre[z] + cv[z];
        for (int y = x, c = 1; y != z; y = f[y], ++c) 
            ans[oq[i]] = max(ans[oq[i]], max(mx[ls[x]], mx[rs[x]]) + cnt[x][c] + pre[f[y]] - pre[z] + mx[y == ls[f[y]] ? rs[f[y]] : ls[f[y]]] + cv[z]);
    }
    for (int i = 1; i <= q; i++) cout << ans[i] << "\n";
    return 0;
}
posted @ 2025-08-25 14:40  forgotmyhandle  阅读(6)  评论(0)    收藏  举报