C. Range Search Query
遍历每个位置 \(i\),判断 \(S\) 中从 \(i\) 开始的长度为 \(m\) 的子串是否和 \(T\) 匹配,如果是则记 \(o[i] = 1\),否则记 \(o[i] = 0\)
然后维护一个 \(\text{next}\) 数组,\(\text{next}[i]\) 表示从 \(i\) 开始向右出现的第一个 \(T\) 的起始下标
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int q;
string s, t;
cin >> q >> s >> t;
int n = s.size(), m = t.size();
vector<int> o(n);
rep(i, n) {
if (s.substr(i, m) == t) o[i] = 1;
}
vector<int> nxt(n+1, 1e9);
for (int i = n-1; i >= 0; --i) {
nxt[i] = nxt[i+1];
if (o[i]) nxt[i] = i;
}
rep(qi, q) {
int l, r;
cin >> l >> r;
--l;
int ni = nxt[l];
if (ni+m <= r) puts("Yes");
else puts("No");
}
return 0;
}
D. Masking Tape
使用时间戳来记录“最近一次发生的全体变色”与每个格子的“最近一次变成未放置(即移除瓦片)”的时刻,用这些信息判断在某个区间内是否发生了影响该格子的第二种操作。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, q;
cin >> n >> q;
string ans(n, 'a');
int last = -1; char c = 'a';
vector<int> t(n, -1);
vector<bool> tile(n);
rep(qi, q) {
int type;
cin >> type;
if (type == 1) {
int i;
cin >> i;
--i;
if (tile[i]) {
t[i] = qi;
}
else {
if (t[i] < last) ans[i] = c;
}
tile[i] = !tile[i];
}
else {
last = qi;
cin >> c;
}
}
rep(i, n) if (!tile[i]) {
if (t[i] < last) ans[i] = c;
}
cout << ans << '\n';
return 0;
}
E. Wheel Distance
先用环上正反两次松弛把每个环点到汇点的最短距离 \(d[i]\) 预处理好,再对每个查询取顺时针、逆时针弧长与经汇点 \(d[s]+d[t]\) 三者的最小值作为答案。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
inline void chmin(ll& a, ll b) { if (a > b) a = b; }
int main() {
int n, q;
cin >> n >> q;
vector<int> a(n);
vector<ll> d(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> d[i];
vector<ll> sa(n+1);
rep(i, n) sa[i+1] = sa[i]+a[i];
rep(ri, 2) {
rep(i, n) chmin(d[(i+1)%n], d[i]+a[i]);
for (int i = n-1; i >= 0; --i) {
chmin(d[i], d[(i+1)%n]+a[i]);
}
}
rep(qi, q) {
int s, t;
cin >> s >> t;
--s; --t;
if (s > t) swap(s, t);
ll ans = 0;
if (t == n) {
ans = d[s];
}
else {
ans = d[s]+d[t];
ll sum = sa[t]-sa[s];
chmin(ans, sum);
chmin(ans, sa[n]-sum);
}
cout << ans << '\n';
}
return 0;
}
F. Count Cells in a Window
扫描线板子
把每个查询对行区间 \([A,B]\) 的求和转成前缀差:答案 =(前 \(B\) 行在列区间
\([C,D]\) 的黑格数) −(前 \(A−1\) 行在列区间 \([C,D]\) 的黑格数)。
对于每个列区间用线段树维护区间加以及区间求和即可。
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct S {
ll sum, len;
};
S op(S a, S b) { return S(a.sum+b.sum, a.len+b.len); }
S e() { return S(0, 0); }
S mapping(ll f, S x) { return S(x.sum + f*x.len, x.len); }
ll composition(ll f, ll g) { return f+g; }
ll id() { return 0; }
int main() {
int n, m, q;
cin >> n >> m >> q;
vector<int> L(n), R(n);
rep(i, n) cin >> L[i] >> R[i], --L[i];
vector<vector<tuple<int, int, int>>> qs(n);
rep(qi, q) {
int u, d, l, r;
cin >> u >> d >> l >> r;
u -= 2; --d; --l;
if (u >= 0) qs[u].emplace_back(l, r, q+qi);
qs[d].emplace_back(l, r, qi);
}
lazy_segtree<S, op, e, ll, mapping, composition, id> seg(m);
rep(i, m) seg.set(i, S(0, 1));
vector<ll> ans(q);
rep(i, n) {
seg.apply(L[i], R[i], 1);
for (auto& [l, r, qi] : qs[i]) {
int sign = 1;
if (qi >= q) qi -= q, sign = -1;
ans[qi] += seg.prod(l, r).sum * sign;
}
}
rep(i, q) cout << ans[i] << '\n';
return 0;
}
G. Frequency Query on Tree
树上莫队板子
记 \(\text{cnt}(y)\) 表示数值 \(y\) 在当前路径上的出现次数,\(g(i)\) 表示满足 \(\text{cnt}(y) \geqslant i\) 的数值 \(y\) 的个数
那么询问的答案就是 \(g(a)-g(b+1)\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using A = array<int, 6>;
template<typename T=int>
struct lca {
int n, l;
vector<vector<int>> to;
vector<vector<T>> co;
vector<int> dep;
vector<T> costs;
vector<vector<int>> par;
lca(int n): n(n), to(n), co(n), dep(n), costs(n) {
l = 0;
while (1<<l <= n) ++l;
par = vector<vector<int>>(n, vector<int>(l, -1));
}
void addEdge(int a, int b, T c=1) {
to[a].push_back(b); co[a].push_back(c);
to[b].push_back(a); co[b].push_back(c);
}
void dfs(int v, int d=0, T c=0, int p=-1) {
par[v][0] = p;
dep[v] = d;
costs[v] = c;
rep(i, to[v].size()) {
int u = to[v][i];
if (u == p) continue;
dfs(u, d+1, c+co[v][i], v);
}
}
void init(int root=0) {
dfs(root);
rep(i, l-1) {
rep(v, n) {
par[v][i+1] = par[v][i]==-1 ? -1 : par[par[v][i]][i];
}
}
}
// LCA
int operator()(int a, int b) {
if (dep[a] > dep[b]) swap(a, b);
int gap = dep[b]-dep[a];
for (int i = l-1; i >= 0; --i) {
int len = 1<<i;
if (gap >= len) {
gap -= len;
b = par[b][i];
}
}
if (a == b) return a;
for (int i = l-1; i >= 0; --i) {
int na = par[a][i];
int nb = par[b][i];
if (na != nb) a = na, b = nb;
}
return par[a][0];
}
int length(int a, int b) {
int c = (*this)(a, b);
return dep[a]+dep[b]-dep[c]*2;
}
T dist(int a, int b) {
int c = (*this)(a, b);
return costs[a]+costs[b]-costs[c]*2;
}
};
int main() {
cin.tie(nullptr) -> sync_with_stdio(false);
int n, q;
cin >> n >> q;
vector<int> x(n);
rep(i, n) cin >> x[i], --x[i];
lca g(n);
rep(i, n-1) {
int u, v;
cin >> u >> v;
--u; --v;
g.addEdge(u, v);
}
g.init();
vector<int> et;
vector<int> st(n), ed(n);
auto dfs = [&](auto& f, int v, int p=-1) -> void {
st[v] = et.size();
et.push_back(v);
for (int u : g.to[v]) if (u != p) f(f, u, v);
ed[v] = et.size();
et.push_back(v);
};
dfs(dfs, 0);
vector<A> qs(q);
rep(i, q) {
int s, t, a, b;
cin >> s >> t >> a >> b;
--s; --t;
if (st[s] > st[t]) swap(s, t);
int lca = g(s, t);
qs[i][3] = a;
qs[i][4] = b;
qs[i][5] = i;
if (lca == s) {
qs[i][0] = st[s];
qs[i][1] = st[t];
qs[i][2] = -1;
}
else {
qs[i][0] = ed[s];
qs[i][1] = st[t];
qs[i][2] = lca;
}
}
int D = max<int>(1, et.size()/sqrt(q));
vector<int> block(q);
rep(i, q) block[i] = qs[i][0]/D;
sort(qs.begin(), qs.end(), [&](const A& a, const A& b) {
if (block[a[5]] != block[b[5]]) return block[a[5]] < block[b[5]];
return a[1] < b[1];
});
vector<bool> used(n);
vector<int> cnt(n), G(n+2);
auto upd = [&](int v) {
int nx = x[v];
if (used[v]) {
--G[cnt[nx]];
--cnt[nx];
used[v] = false;
}
else {
++cnt[nx];
++G[cnt[nx]];
used[v] = true;
}
};
vector<int> ans(q);
int l = 0, r = -1;
for (auto& [ql, qr, lca, a, b, qi] : qs) {
while (r < qr) upd(et[++r]);
while (l > ql) upd(et[--l]);
while (r > qr) upd(et[r--]);
while (l < ql) upd(et[l++]);
if (lca != -1) upd(lca);
ans[qi] = G[a]-G[b+1];
if (lca != -1) upd(lca);
}
rep(i, q) cout << ans[i] << '\n';
return 0;
}
浙公网安备 33010602011771号