题意:
给出一个长为 $n$ 的数列 $a_1ldots a_n$ ,以及 $n$ 个操作,操作涉及区间开方,区间求和。
有多组测试数据。
Solution:
这道题可谓是真·暴力
区间操作,显然线段树。
我们发现不断开放下降很快,几次就搞定了,而0和1开方还是自己,所以我们在线段树的节点上记录一个标记flag确定一个区间内的数是不是都是0或1。
修改时如果发现一个当前区间已经全是0或1了回溯即可。
查询类似区间查询。其实就是一个单点修改+区间查询,不过每个点没修改的次数不会超过10。
有几个坑点:
1,它给你的区间有可能l>r
2,注意多组数据
#include <iostream> #include <cstdio> #include <cmath> using namespace std; const long long MAX = 100010; struct node{ long long l, r; long long val; bool flag; }t[MAX * 4]; long long n, s[MAX], q; inline void build(long long l, long long r, long long id) { t[id].l = l, t[id].r = r; t[id].val = t[id].flag = 0; if (l == r) { t[id].val = s[l]; return; } long long mid = (l + r) >> 1; build(l, mid, id * 2); build(mid + 1, r, id * 2 + 1); t[id].val = t[id * 2].val + t[id * 2 + 1].val; } inline void change(long long p, long long l, long long r) { long long _l = t[p].l, _r = t[p].r; if (t[p].flag) return; if (_l == _r) { t[p].val = sqrt(t[p].val); if (t[p].val <= 1) t[p].flag = 1; return; } long long mid = (_l + _r) >> 1; if (l <= mid) change(p * 2, l, r); if (r > mid) change(p * 2 + 1, l, r); t[p].val = t[p * 2].val + t[p * 2 + 1].val; if (t[p * 2].flag && t[p * 2 + 1].flag) t[p].flag = 1; } inline long long ask(long long p, long long l, long long r) { long long _l = t[p].l, _r = t[p].r; if (_l >= l && _r <= r) { return t[p].val; } long long mid = (_l + _r) >> 1; long long ret = 0; if (l <= mid) ret += ask(p * 2, l, r); if (r > mid) ret += ask(p * 2 + 1, l, r); return ret; } long long CRZzzz; int main() { while (scanf("%lld", &n) != EOF) { CRZzzz++; printf("Case #%lld: ", CRZzzz); for (long long i = 1; i <= n; i++) { scanf("%lld", &s[i]); } build(1, n, 1); scanf("%lld", &q); while (q--) { long long opt, x, y; scanf("%lld%lld%lld", &opt, &x, &y); if (x > y) swap(x, y); if (opt == 1) { printf("%lld ", ask(1, x, y)); } else { change(1, x, y); } } printf(" "); } return 0; }