HDU-4027-Can you answer these queries?线段树+区间根号+剪枝
传送门Can you answer these queries?
题意:
线段树,只是区间修改变成 把每个点的值开根号;
思路:
对$[X,Y]$的值开根号,由于最大为 $2^{63}$.可以观察到最多开根号7次即为1,则当根号次数大于等于7时,这段区间值为$R-L+1$,还有一点是L可能大于R。
以下来自鸟神:(真是强啊)
据这一性质,我们可以得到一种解决方案:对于修改,我们对于区间内的数不全为1的区间更新,直到遇到区间内的数全部为1的区间或者叶子结点为止。这样只要使用线段树,维护区间和的信息即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstring> #include <algorithm> #include <string> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; const int maxn = 100009; ll a[maxn], sum[maxn * 4]; int n, m; void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void buildup(int l, int r, int rt) { if (l == r) { sum[rt] = a[l]; return; } int mid = (l + r) >> 1; buildup(l, mid, rt << 1); buildup(mid + 1, r, rt << 1 | 1); pushup(rt); } void update(int L, int R, int l, int r, int rt) { if (sum[rt] == r - l + 1) return; // 剪枝 if (l == r) { sum[rt] = (int)sqrt(sum[rt]); return; } int mid = (l + r) >> 1; if (mid >= L) update(L, R, l, mid, rt << 1); if (R > mid) update(L, R, mid + 1, r, rt << 1 | 1); pushup(rt); } ll query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return sum[rt]; } ll ans = 0; int mid = (l + r) >> 1; if (mid >= L) ans += query(L, R, l, mid, rt << 1); if (R > mid) ans += query(L, R, mid + 1, r, rt << 1 | 1); return ans; } int main() { int cnt = 0; while (~scanf("%d", &n)) { printf("Case #%d:\n", ++cnt); memset(a, 0, sizeof(a)); memset(sum, 0, sizeof(sum)); for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } buildup(1, n, 1); scanf("%d", &m); for (int i = 1; i <= m; i++) { int op, a, b; scanf("%d%d%d", &op, &a, &b); if (a > b) swap(a, b); if (op == 1) { ll ans = query(a, b, 1, n, 1); printf("%lld\n", ans); } else { update(a, b, 1, n, 1); } } printf("\n"); } return 0; }
skr