2025/10/27~2025/11/2 做题笔记
2025/10/27
第一代图灵机
一样的套路,考虑每一个右端点对应的最左边可以到哪里,显然是最小的 \(j\) 使得 \(\max\limits_{j \le k \le i}pre_k = j - 1\)。考虑线段树维护一个区间内的最大的答案和最大的 \(pre_i\),但是发现当 \(pushup\) 的时候不好判断右区间对整个区间的贡献,所以需要维护一个区间中右半边区间对答案的贡献。不过最后可以发现一个区间内最大的答案也没什么用,没办法只通过它算出一个区间内指定一个最小 \(pre\) 的答案,还是只能用 \(pushup\) 算出来
Code
#include <iostream>
#include <set>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
const int kN = 2e5 + 1;
int n, m, q, c[kN];
set<int> s[kN];
ll a[kN];
struct Tr {
int mx;
ll val;
} tr[kN * 4];
ll Pushup(int mx, int x, int l, int r) {
if (l == r)
return a[l] - a[max(mx, tr[x].mx)];
int m = (l + r) / 2;
if (mx > tr[x * 2].mx)
return max(a[m] - a[mx], Pushup(mx, x * 2 + 1, m + 1, r));
return max(tr[x].val, Pushup(mx, x * 2, l, m));
}
void Update(int p, int k, int x = 1, int l = 1, int r = n) {
if (l == r)
return tr[x].mx = k, void();
int m = (l + r) / 2;
if (p <= m)
Update(p, k, x * 2, l, m);
else
Update(p, k, x * 2 + 1, m + 1, r);
tr[x].mx = max(tr[x * 2].mx, tr[x * 2 + 1].mx), tr[x].val = Pushup(tr[x * 2].mx, x * 2 + 1, m + 1, r);
}
ll Query(int mx, int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return Pushup(mx, x, l, r);
int m = (l + r) / 2;
ll res = 0;
if (nl <= m)
res = Query(mx, nl, nr, x * 2, l, m);
if (nr > m)
res = max(res, Query(max(mx, tr[x * 2].mx), nl, nr, x * 2 + 1, m + 1, r));
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m >> q;
for (int i = 1; i <= m; i++)
s[i].insert(0);
for (int i = 1; i <= n; i++)
cin >> a[i], a[i] += a[i - 1];
for (int i = 1; i <= n; i++) {
cin >> c[i];
Update(i, *s[c[i]].rbegin()), s[c[i]].insert(i);
}
for (int op, l, r; q--;) {
cin >> op >> l >> r;
if (op - 1) {
auto it = s[c[l]].find(l);
if (next(it) != s[c[l]].end())
Update(*next(it), *prev(it));
s[c[l]].erase(l), c[l] = r;
it = s[c[l]].lower_bound(l);
if (it != s[c[l]].end())
Update(*it, l);
Update(l, *prev(it)), s[c[l]].insert(l);
} else {
cout << Query(l - 1, l, r) << '\n';
}
}
return 0;
}
P2617 Dynamic Rankings
之前一直没有理解主席树套树状数组,现在感觉叫做树状数组套权值线段树更合适吧???
Code
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int kN = 1e6 + 1;
int n, m, tot, cnt, a[kN], rt[kN], b[kN * 2];
vector<int> vl, vr;
map<int, int> mp;
struct Tr {
int l, r, cnt;
} tr[kN * 20];
struct Query {
int op, l, r, k;
} q[kN];
void Update(int& x, int p, int v, int l = 1, int r = tot) {
x = !x ? ++cnt : x;
tr[x].cnt += v;
if (l == r)
return;
int m = (l + r) / 2;
if (p <= m)
return Update(tr[x].l, p, v, l, m);
Update(tr[x].r, p, v, m + 1, r);
}
void Modify(int x, int t, int v) {
for (; x <= n; x += x & -x)
Update(rt[x], t, v);
}
int Query(int l, int r, int k) {
if (l == r)
return l;
int m = (l + r) / 2, res = 0;
for (int i : vl)
res -= tr[tr[i].l].cnt;
for (int i : vr)
res += tr[tr[i].l].cnt;
if (k <= res) {
for (int& i : vl)
i = tr[i].l;
for (int& i : vr)
i = tr[i].l;
return Query(l, m, k);
}
for (int& i : vl)
i = tr[i].r;
for (int& i : vr)
i = tr[i].r;
return Query(m + 1, r, k - res);
}
int Ask(int l, int r, int k) {
vl.clear(), vr.clear();
for (; r; r -= r & -r)
vr.push_back(rt[r]);
for (--l; l; l -= l & -l)
vl.push_back(rt[l]);
int t = Query(1, tot, k);
return b[t];
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i], b[++tot] = a[i];
for (int i = 1; i <= m; i++) {
char ch;
cin >> ch >> q[i].l >> q[i].r;
if (ch == 'Q')
cin >> q[i].k, q[i].op = 1;
else
b[++tot] = q[i].r;
}
sort(b + 1, b + tot + 1);
for (int i = 1; i <= tot; i++)
mp[b[i]] = i;
for (int i = 1; i <= n; i++)
Modify(i, mp[a[i]], 1);
for (int i = 1; i <= m; i++) {
int l = q[i].l, r = q[i].r, k = q[i].k;
if (q[i].op)
cout << Ask(l, r, k) << '\n';
else
Modify(l, mp[a[l]], -1), Modify(l, mp[r], 1), a[l] = r;
}
return 0;
}
/*
2 4 1 3 5
*/
2025/10/28
queue
挂分原因:起始点的范围是 \(w - (n - 1) * d\) 而不是 \(n\),实在是过于唐了
Code
#include <algorithm>
#include <iostream>
using namespace std;
const int kN = 3e5 + 1;
int n, w, ans = 1e9, a[kN], b[kN];
int Calc(int x) {
int c = 0;
for (int i = 1; i <= n; i++)
if (a[i] - (i - 1) * x > 0)
b[a[i] - (i - 1) * x]++;
int t = *max_element(b + 1, b + w - (n - 1) * x + 1);
for (int i = 1; i <= n; i++)
b[max(a[i] - (i - 1) * x, 0)] = 0;
return n - t;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("queue.in", "r", stdin);
freopen("queue.out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> n >> w;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 0; 1 + i * (n - 1) <= w; i++)
ans = min(ans, Calc(i));
cout << ans;
return 0;
}
yugo
和上次 T4 把每个点的度数变为偶数的做法完全一样,不懂为什么一个人都没过,大概是都像我一样忘记图可以不连通了吧/kk
Code
#include <iostream>
#include <vector>
using namespace std;
using pii = pair<int, int>;
const int kN = 1e6 + 1;
int T, n, m, t, ans, v[kN], d[kN], dep[kN];
vector<pii> e[kN];
struct Ed {
int x, y, v;
} ed[kN];
void Dfs(int x, int fa, int id) {
dep[x] = dep[fa] + 1;
for (auto [i, id] : e[x]) {
if (i == fa)
continue;
if (!dep[i])
d[i] ^= 1, Dfs(i, x, id);
else if (dep[i] < dep[x])
d[x] ^= 1, ed[id].v = x;
}
if (d[x]) {
if (x == t)
ans = 1;
else
d[fa] ^= 1, ed[id].v = fa;
} else
ed[id].v = x;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("yugo.in", "r", stdin);
freopen("yugo.out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> T;
cin >> n >> m;
for (int i = 1, x, y; i <= m; i++)
cin >> x >> y, ed[i] = {x, y, 0}, e[x].push_back({y, i}), e[y].push_back({x, i});
for (int i = 1; i <= n; i++)
if (!dep[i])
Dfs(t = i, 0, 0);
if (ans) {
cout << "Yugoslavia is unstable!\n";
return 0;
}
for (int i = 1; i <= m; i++) {
int s = 2 * v[ed[i].v] + 1;
cout << s + (ed[i].v == ed[i].y) << ' ';
v[ed[i].v] ^= 1;
}
return 0;
}
2025/10/29
CF1340F Nastya and CBS
感觉思维难度也没那么难,可能是已经知道了这道题是线段树+hash吧()
肯定是一道数据结构题,考虑使用线段树维护一个区间。思考线段树应给维护哪些东西:已经匹配的括号显然没用了,那么只需要考虑剩下来的括号。因为括号不能交叉,那么有可能形成匹配的括号的区间只可能形如左边一堆左括号+右边一堆右括号。所以线段树每个区间维护的是当前区间的剩余的右括号、左括号以及该区间是否已经产生了不合法的括号对
考虑合并两个区间,会分三种情况考虑
- \(lson\) 的左括号多于 \(rson\) 的右括号。取出 \(lson\) 的一段后缀,如果能与 \(rson\) 完全匹配上,那么把剩余的左括号拼到 \(rson\) 的左括号上
- \(lson\) 的左括号少于 \(rson\) 的右括号。同理
- \(lson\) 的左括号等于 \(rson\) 的右括号,直接继承即可
理顺一下思路,需要的关键函数有:取出左边区间的一段后缀、取出右边区间的一段前缀、合并区间
代码对我来说很难写,一直在纠结怎么取出查询时的暂时的前后缀。看了眼巨巨宙的代码,发现前后缀直接去线段树区间上的区间去取就行了,写的是真的优雅。当然也可以暂时建几个结点,但是这样就太丑陋了
Code
#include <iostream>
using namespace std;
const int kN = 1e5 + 1, kM = 998244853, kB = 1e5 + 3, kI = 953914129;
int n, q, B[kN * 2], *b = B + kN;
struct Tr {
int l[2], h[2];
bool v;
} tr[kN * 4];
int LHash(int x, int len) {
if (len == 0)
return 0;
if (tr[x].l[1] == len)
return tr[x].h[1];
if (len <= tr[x * 2 + 1].l[1])
return LHash(x * 2 + 1, len);
int l = tr[x * 2 + 1].l[1] - tr[x * 2 + 1].l[0], t = LHash(x * 2, len - l);
return ((1ll * t - tr[x * 2 + 1].h[0] + kM) % kM * b[l] % kM + tr[x * 2 + 1].h[1]) % kM;
}
int RHash(int x, int len) {
if (len == 0)
return 0;
if (tr[x].l[0] == len)
return tr[x].h[0];
if (len <= tr[x * 2].l[0])
return RHash(x * 2, len);
int l = tr[x * 2].l[0] - tr[x * 2].l[1], t = RHash(x * 2 + 1, len - l);
return ((1ll * t - tr[x * 2].h[1] + kM) % kM * b[l] % kM + tr[x * 2].h[0]) % kM;
}
Tr Merge(int x, Tr ls, Tr rs) {
int mn = min(ls.l[1], rs.l[0]);
Tr ret = {{ls.l[0] + rs.l[0] - mn, ls.l[1] + rs.l[1] - mn}, {ls.h[0], rs.h[1]}, 1};
if (ls.v || rs.v);
else if (ls.l[1] > rs.l[0]) {
if (LHash(x * 2, rs.l[0]) == rs.h[0])
ret.h[1] = ((1ll * ls.h[1] - rs.h[0] + kM) % kM * b[rs.l[1] - rs.l[0]] % kM + rs.h[1]) % kM, ret.v = 0;
} else if (ls.l[1] < rs.l[0]) {
if (RHash(x * 2 + 1, ls.l[1]) == ls.h[1])
ret.h[0] = ((1ll * rs.h[0] - ls.h[1] + kM) % kM * b[ls.l[0] - ls.l[1]] % kM + ls.h[0]) % kM, ret.v = 0;
} else if (ls.h[1] == rs.h[0])
ret.v = 0;
return ret;
}
void Update(int p, int v, int x = 1, int l = 1, int r = n) {
if (l == r) {
if (v > 0)
tr[x] = {{0, 1}, {0, v}, 0};
else
tr[x] = {{1, 0}, {-v, 0}, 0};
return;
}
int m = (l + r) / 2;
if (p <= m)
Update(p, v, x * 2, l, m);
else
Update(p, v, x * 2 + 1, m + 1, r);
tr[x] = Merge(x, tr[x * 2], tr[x * 2 + 1]);
}
Tr Query(int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return tr[x];
int m = (l + r) / 2;
if (nl <= m && nr > m)
return Merge(x, Query(nl, nr, x * 2, l, m), Query(nl, nr, x * 2 + 1, m + 1, r));
if (nl <= m)
return Query(nl, nr, x * 2, l, m);
return Query(nl, nr, x * 2 + 1, m + 1, r);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
b[0] = 1;
for (int i = 1; i < kN; i++)
b[i] = 1ll * b[i - 1] * kB % kM;
for (int i = -1; i > -kN; i--)
b[i] = 1ll * b[i + 1] * kI % kM;
cin >> n >> q;
for (int i = 1, x; i <= n; i++)
cin >> x, Update(i, x);
cin >> q;
for (int op, l, r; q--;) {
cin >> op >> l >> r;
if (op == 1) {
Update(l, r);
continue;
}
Tr t = Query(l, r);
cout << (t.h[0] == 0 && t.h[1] == 0 && t.v == 0 ? "Yes\n" : "No\n");
}
return 0;
}
P4145 上帝造题的七分钟 2 / 花神游历各国
注意到每一个点最多开 $ \mathcal{O} (1)$ 次根,当一个区间内的点全部都变成 1 后不去管他就行了。特别要注意可能 \(l > r\)
Code
#include <chrono>
#include <cmath>
#include <iostream>
using namespace std;
using ll = long long;
const int kN = 1e5 + 1;
int n, q;
ll a[kN];
struct Tr {
bool tag;
ll sum;
} tr[kN * 4];
void Find(int x, int l, int r) {
if (l == r) {
tr[x].sum = sqrt(tr[x].sum), tr[x].tag = tr[x].sum == 1;
return;
}
int m = (l + r) / 2;
if (!tr[x * 2].tag)
Find(x * 2, l, m);
if (!tr[x * 2 + 1].tag)
Find(x * 2 + 1, m + 1, r);
tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum, tr[x].tag = tr[x * 2].tag & tr[x * 2 + 1].tag;
}
void Update(int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return Find(x, l, r);
int m = (l + r) / 2;
if (nl <= m)
Update(nl, nr, x * 2, l, m);
if (nr > m)
Update(nl, nr, x * 2 + 1, m + 1, r);
tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum, tr[x].tag = tr[x * 2].tag & tr[x * 2 + 1].tag;
}
ll Query(int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return tr[x].sum;
int m = (l + r) / 2;
if (nl <= m && m < nr)
return Query(nl, nr, x * 2, l, m) + Query(nl, nr, x * 2 + 1, m + 1, r);
if (nl <= m)
return Query(nl, nr, x * 2, l, m);
return Query(nl, nr, x * 2 + 1, m + 1, r);
}
void Build(int x = 1, int l = 1, int r = n) {
tr[x].tag = 0;
if (l == r)
return tr[x].sum = a[l], void();
int m = (l + r) / 2;
Build(x * 2, l, m), Build(x * 2 + 1, m + 1, r);
tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
Build();
cin >> q;
for (int op, l, r; q--;) {
cin >> op >> l >> r;
if (l > r)
swap(l, r);
if (op)
cout << Query(l, r) << '\n';
else
Update(l, r);
}
return 0;
}
「雅礼集训 2017 Day1」市场
虽然每个点除以 \(\log\) 次,但是还有加法操作会使得一切回到起点,这时候我们可以想到当一段区间变成 \(-1/0\) 的时候可以统一操作,这样可能是对的,但是我不会维护这个 \(tag\),遂以失败告终。
有更加巧妙的做法。考虑到一个区间要是能统一操作会很舒服,那么会想到要么使得区间中的变化量相同或者答案相同,但是答案相同显然不行,那么思考区间中的变化量相同会满足什么条件。容易发现,只有 \(max\) 和 \(min\) 两个值是重要的,因为 \(x - \left\lfloor\dfrac{x}{d}\right\rfloor\) 是单调的,同时发现 \(max\) 和 \(min\) 的性质非常良好,因为每有一次操作 2, \(max - min\) 会至少减少一半,同时加法操作至多只会影响两对 \(max\) 和 \(min\),于是只用维护区间加法操作即可
貌似维护 \(max\) 和 \(min\) 是一个套路,因为简单的加法减法不会对 \(max - min\) 产生太大的影响,但是如果是乘除法影响就会很大。
Code
#include <cmath>
#include <iostream>
using namespace std;
using ll = long long;
const int kN = 1e5 + 1;
int n, q;
struct Tr {
ll mx, mn, sum, tag;
} tr[kN * 4];
void Func(int x, int l, int r, ll k) {
tr[x].mx += k, tr[x].mn += k, tr[x].sum += (r - l + 1) * k, tr[x].tag += k;
}
void Pushdown(int x, int l, int r) {
int m = (l + r) / 2;
Func(x * 2, l, m, tr[x].tag), Func(x * 2 + 1, m + 1, r, tr[x].tag), tr[x].tag = 0;
}
void Add(int nl, int nr, int k, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return Func(x, l, r, k);
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nl <= m)
Add(nl, nr, k, x * 2, l, m);
if (nr > m)
Add(nl, nr, k, x * 2 + 1, m + 1, r);
tr[x].mn = min(tr[x * 2].mn, tr[x * 2 + 1].mn), tr[x].mx = max(tr[x * 2].mx, tr[x * 2 + 1].mx), tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum;
}
void Divide(int nl, int nr, int k, int x = 1, int l = 1, int r = n) {
ll t = tr[x].mx - floor(1.0 * tr[x].mx / k), _t = tr[x].mn - floor(1.0 * tr[x].mn / k);
if (nl <= l && r <= nr && t == _t)
return Func(x, l, r, -t);
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nl <= m)
Divide(nl, nr, k, x * 2, l, m);
if (nr > m)
Divide(nl, nr, k, x * 2 + 1, m + 1, r);
tr[x].mn = min(tr[x * 2].mn, tr[x * 2 + 1].mn), tr[x].mx = max(tr[x * 2].mx, tr[x * 2 + 1].mx), tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum;
}
ll QueryMin(int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return tr[x].mn;
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nr <= m)
return QueryMin(nl, nr, x * 2, l, m);
if (nl > m)
return QueryMin(nl, nr, x * 2 + 1, m + 1, r);
return min(QueryMin(nl, nr, x * 2, l, m), QueryMin(nl, nr, x * 2 + 1, m + 1, r));
}
ll QuerySum(int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return tr[x].sum;
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nr <= m)
return QuerySum(nl, nr, x * 2, l, m);
if (nl > m)
return QuerySum(nl, nr, x * 2 + 1, m + 1, r);
return QuerySum(nl, nr, x * 2, l, m) + QuerySum(nl, nr, x * 2 + 1, m + 1, r);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> n >> q;
for (int i = 1, x; i <= n; i++)
cin >> x, Add(i, i, x);
for (int op, l, r, d; q--;) {
cin >> op >> l >> r, l++, r++;
if (op == 1)
cin >> d, Add(l, r, d);
else if (op == 2)
cin >> d, Divide(l, r, d);
else if (op == 3)
cout << QueryMin(l, r) << '\n';
else
cout << QuerySum(l, r) << '\n';
}
return 0;
}
#228. 基础数据结构练习题
和上一题的维护方法一样
Code
#include <cmath>
#include <iostream>
using namespace std;
using ll = long long;
const int kN = 1e5 + 1;
int n, q;
struct Tr {
ll mx, mn, sum, tag;
} tr[kN * 4];
void Func(int x, int l, int r, ll k) {
tr[x].mx += k, tr[x].mn += k, tr[x].sum += (r - l + 1) * k, tr[x].tag += k;
}
void Pushdown(int x, int l, int r) {
int m = (l + r) / 2;
Func(x * 2, l, m, tr[x].tag), Func(x * 2 + 1, m + 1, r, tr[x].tag), tr[x].tag = 0;
}
void Add(int nl, int nr, int k, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return Func(x, l, r, k);
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nl <= m)
Add(nl, nr, k, x * 2, l, m);
if (nr > m)
Add(nl, nr, k, x * 2 + 1, m + 1, r);
tr[x].mn = min(tr[x * 2].mn, tr[x * 2 + 1].mn), tr[x].mx = max(tr[x * 2].mx, tr[x * 2 + 1].mx), tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum;
}
void Sqrt(int nl, int nr, int x = 1, int l = 1, int r = n) {
ll t = tr[x].mx - floor(sqrt(tr[x].mx)), _t = tr[x].mn - floor(sqrt(tr[x].mn));
if (nl <= l && r <= nr && t == _t)
return Func(x, l, r, -t);
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nl <= m)
Sqrt(nl, nr, x * 2, l, m);
if (nr > m)
Sqrt(nl, nr, x * 2 + 1, m + 1, r);
tr[x].mn = min(tr[x * 2].mn, tr[x * 2 + 1].mn), tr[x].mx = max(tr[x * 2].mx, tr[x * 2 + 1].mx), tr[x].sum = tr[x * 2].sum + tr[x * 2 + 1].sum;
}
ll Query(int nl, int nr, int x = 1, int l = 1, int r = n) {
if (nl <= l && r <= nr)
return tr[x].sum;
Pushdown(x, l, r);
int m = (l + r) / 2;
if (nr <= m)
return Query(nl, nr, x * 2, l, m);
if (nl > m)
return Query(nl, nr, x * 2 + 1, m + 1, r);
return Query(nl, nr, x * 2, l, m) + Query(nl, nr, x * 2 + 1, m + 1, r);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(0)->sync_with_stdio(0);
cin >> n >> q;
for (int i = 1, x; i <= n; i++)
cin >> x, Add(i, i, x);
for (int op, l, r, d; q--;) {
cin >> op >> l >> r;
if (op == 1)
cin >> d, Add(l, r, d);
else if (op == 2)
Sqrt(l, r);
else
cout << Query(l, r) << '\n';
}
return 0;
}

浙公网安备 33010602011771号