对区间进行操作:操作0是区间内的每个点的值val = int(sqrt(val)); 操作1是查询区间和。
因为是区间操作,第一感觉是lazy,但是这题lazy在push_down的时候无法快速的对区间进行更新,所以变成点操作+剪枝。留意到每个点的值必然是正整数,且开根几次之后最终都会稳定在1,所以说一个节点表示的范围是[l,r]时,若sum[rt]=l-r+1,必然下面的每个节点都是1,不必再开根了。剪完这个枝就能过。
#include <iostream> #include <bits/stdc++.h> using namespace std; #define ll long long #define mst(a,b) memset(a,b,sizeof(a)) #define rep(i,a,b) for(ll i=(a);i<(b);++i) const double eps = 1e-8, PI = acos(-1.0f); const int inf = 0x3f3f3f3f, maxN = 1e5 + 5; int N, M, T; // Segment tree #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define lch rt << 1 #define rch rt << 1 | 1 ll seg[maxN << 2]; void pushUp(int rt) { seg[rt] = seg[lch] + seg[rch]; } void init(int l, int r, int rt) { if (l == r) { scanf("%lld", &seg[rt]); return; } int m = (l + r) >> 1; init(lson); init(rson); pushUp(rt); } void update(int L, int R, int l, int r, int rt) { if (l == r) { seg[rt] = sqrt(seg[rt]); return; } if (L <= l && r <= R && seg[rt] == r - l + 1) return; int m = (l + r) >> 1; if (L <= m) update(L, R, lson); if (R > m) update(L, R, rson); pushUp(rt); } ll query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return seg[rt]; } int m = (l + r) >> 1; ll ans = 0; if (L <= m) ans += query(L, R, lson); if (R > m) ans += query(L, R, rson); return ans; } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif int cas = 1; while (~scanf("%d", &N)) { init(1, N, 1); scanf("%d", &M); int a, b, c; printf("Case #%d: ", cas++); rep(i, 0, M) { scanf("%d%d%d", &a, &b, &c); if (b > c) swap(b, c); if (a == 1) printf("%lld ", query(b, c, 1, N, 1)); else update(b, c, 1, N, 1); } puts(""); } return 0; }