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;
}