Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:
Yuta has an array A with n numbers. Then he makes m operations on it.
There are three type of operations:
1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to ⌊A√[i]⌋
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]
It is too difficult for Rikka. Can you help her?
Yuta has an array A with n numbers. Then he makes m operations on it.
There are three type of operations:
1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to ⌊A√[i]⌋
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]
It is too difficult for Rikka. Can you help her?
Input
The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.
For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.
It is guaranteed that 1<=A[i],x<=100000.
For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.
It is guaranteed that 1<=A[i],x<=100000.
Output
For each operation of type 3, print a lines contains one number -- the answer of the query.
Sample Input
1 5 5 1 2 3 4 5 1 3 5 2 2 1 4 3 2 4 2 3 5 3 1 5
Sample Output
5 6线段树的暴力更新,可以想象,sqrt操作的下降速度是很快的于是每个节点维护最大和最小值,当sqrt操作是暴力的传递下去,当最大值和最小值的sqrt相同时就无需下传了。#include<set> #include<map> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<bitset> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define rep(i,j,k) for (int i = j; i <= k; i++) #define per(i,j,k) for (int i = j; i >= k; i--) #define lson x << 1, l, mid #define rson x << 1 | 1, mid + 1, r #define fi first #define se second #define mp(i,j) make_pair(i,j) #define pii pair<int,int> using namespace std; typedef long long LL; const int low(int x) { return x&-x; } const double eps = 1e-8; const int INF = 0x7FFFFFFF; const int mod = 1e9 + 7; const int N = 4e5 + 10; const int read() { char ch = getchar(); while (ch<'0' || ch>'9') ch = getchar(); int x = ch - '0'; while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0'; return x; } int T, n, m, l, r, x, type; LL f[N], L[N], R[N], a[N]; int g(LL x) { return (int)sqrt(1.0*x); } void up(int x) { L[x] = min(L[x << 1], L[x << 1 | 1]); R[x] = max(R[x << 1], R[x << 1 | 1]); f[x] = f[x << 1] + f[x << 1 | 1]; } void build(int x, int l, int r) { a[x] = 0; if (l == r) { scanf("%d", &f[x]); R[x] = L[x] = f[x]; } else { int mid = l + r >> 1; build(lson); build(rson); up(x); } } void push(int x, int l, int r) { if (a[x]) { a[x << 1] += a[x]; L[x << 1] += a[x]; R[x << 1] += a[x]; f[x << 1] += 1LL * a[x] * ((l + r >> 1) - l + 1); a[x << 1 | 1] += a[x]; L[x << 1 | 1] += a[x]; R[x << 1 | 1] += a[x]; f[x << 1 | 1] += 1LL * a[x] * (r - (l + r >> 1)); a[x] = 0; } if (L[x] == R[x]) { a[x << 1] = a[x << 1 | 1] = 0; L[x << 1] = R[x << 1] = L[x << 1 | 1] = R[x << 1 | 1] = L[x]; f[x << 1] = 1LL * L[x] * ((l + r >> 1) - l + 1); f[x << 1 | 1] = 1LL * R[x] * (r - (l + r >> 1)); } } void add(int x, int l, int r, int ll, int rr, int v) { if (l < r && (a[x] || L[x] == R[x])) push(x, l, r); if (ll <= l && r <= rr) { a[x] += v; L[x] += v; R[x] += v; f[x] += 1LL * v * (r - l + 1); } else { int mid = l + r >> 1; if (ll <= mid) add(lson, ll, rr, v); if (rr > mid) add(rson, ll, rr, v); up(x); } } void down(int x, int l, int r, int ll, int rr) { if (l < r && (a[x] || L[x] == R[x])) push(x, l, r); if (ll <= l && r <= rr) { if (g(L[x]) == g(R[x])) { L[x] = R[x] = g(L[x]); f[x] = 1LL * L[x] * (r - l + 1); } else { int mid = l + r >> 1; if (ll <= mid) down(lson, ll, rr); if (rr > mid) down(rson, ll, rr); up(x); } } else { int mid = l + r >> 1; if (ll <= mid) down(lson, ll, rr); if (rr > mid) down(rson, ll, rr); up(x); } } LL sum(int x, int l, int r, int ll, int rr) { if (l < r && (a[x] || L[x] == R[x])) push(x, l, r); if (ll <= l && r <= rr) return f[x]; else { int mid = l + r >> 1; LL res = 0; if (ll <= mid) res += sum(lson, ll, rr); if (rr > mid) res += sum(rson, ll, rr); return res; } } int main() { T = read(); while (T--) { scanf("%d%d", &n, &m); build(1, 1, n); while (m--) { type = read(); l = read(); r = read(); if (type == 1) { x = read(); add(1, 1, n, l, r, x); } else { if (type == 2) down(1, 1, n, l, r); else printf("%lld\n", sum(1, 1, n, l, r)); } } } return 0; }
hdu上的数据已经加强了,上述版本会tle。对于加强的数据,之所以超时的原因是数据中出现了sqrt以后仍旧不相等的情况,举个例子,x和x+1,每次加上x^2+x,之后再开方,会保持原来的序列不变,这导致了暴力更新每次是真的暴力。解决这种情况的办法就是再多考虑极差为1的情况,可以想象,对于一段区间连续的加操作和开放操作,值之间的差一定会趋向于0或1,而不会是更大的数。所以在原来的情况下加上判断极差为1的情况,此时的开方操作相当于区间减操作。因为开方前相差1,开方后仍旧是相差1,这样就可以通过加强的数据了。#include<set> #include<map> #include<ctime> #include<cmath> #include<stack> #include<queue> #include<bitset> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define rep(i,j,k) for (int i = j; i <= k; i++) #define per(i,j,k) for (int i = j; i >= k; i--) #define lson x << 1, l, mid #define rson x << 1 | 1, mid + 1, r #define fi first #define se second #define mp(i,j) make_pair(i,j) #define pii pair<int,int> using namespace std; typedef long long LL; const int low(int x) { return x&-x; } const double eps = 1e-8; const int INF = 0x7FFFFFFF; const int mod = 1e9 + 7; const int N = 4e5 + 10; const int read() { char ch = getchar(); while (ch<'0' || ch>'9') ch = getchar(); int x = ch - '0'; while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0'; return x; } int T, n, m, l, r, x, type; LL f[N], L[N], R[N], a[N]; int g(LL x) { return (int)sqrt(1.0*x); } void up(int x) { L[x] = min(L[x << 1], L[x << 1 | 1]); R[x] = max(R[x << 1], R[x << 1 | 1]); f[x] = f[x << 1] + f[x << 1 | 1]; } void build(int x, int l, int r) { a[x] = 0; if (l == r) { R[x] = L[x] = f[x] = read(); } else { int mid = l + r >> 1; build(lson); build(rson); up(x); } } void push(int x, int l, int r) { if (a[x]) { a[x << 1] += a[x]; L[x << 1] += a[x]; R[x << 1] += a[x]; f[x << 1] += 1LL * a[x] * ((l + r >> 1) - l + 1); a[x << 1 | 1] += a[x]; L[x << 1 | 1] += a[x]; R[x << 1 | 1] += a[x]; f[x << 1 | 1] += 1LL * a[x] * (r - (l + r >> 1)); } if (L[x] == R[x]) { L[x << 1] = R[x << 1] = L[x << 1 | 1] = R[x << 1 | 1] = L[x]; f[x << 1] = 1LL * L[x] * ((l + r >> 1) - l + 1); f[x << 1 | 1] = 1LL * R[x] * (r - (l + r >> 1)); } a[x] = 0; } void add(int x, int l, int r, int ll, int rr, int v) { if (l < r && (a[x] || L[x] == R[x])) push(x, l, r); if (ll <= l && r <= rr) { a[x] += v; L[x] += v; R[x] += v; f[x] += 1LL * v * (r - l + 1); } else { int mid = l + r >> 1; if (ll <= mid) add(lson, ll, rr, v); if (rr > mid) add(rson, ll, rr, v); up(x); } } void down(int x, int l, int r, int ll, int rr) { if (l < r && (a[x] || L[x] == R[x])) push(x, l, r); if (ll <= l && r <= rr) { if (g(L[x]) == g(R[x])) { L[x] = R[x] = g(L[x]); f[x] = 1LL * L[x] * (r - l + 1); } else if (L[x] + 1 == R[x]) { int k = R[x] - g(R[x]); add(x, l, r, ll, rr, -k); } else { int mid = l + r >> 1; if (ll <= mid) down(lson, ll, rr); if (rr > mid) down(rson, ll, rr); up(x); } } else { int mid = l + r >> 1; if (ll <= mid) down(lson, ll, rr); if (rr > mid) down(rson, ll, rr); up(x); } } LL sum(int x, int l, int r, int ll, int rr) { if (l < r && (a[x] || L[x] == R[x])) push(x, l, r); if (ll <= l && r <= rr) return f[x]; else { int mid = l + r >> 1; LL res = 0; if (ll <= mid) res += sum(lson, ll, rr); if (rr > mid) res += sum(rson, ll, rr); return res; } } int main() { T = read(); while (T--) { scanf("%d%d", &n, &m); build(1, 1, n); while (m--) { type = read(); l = read(); r = read(); if (type == 1) { x = read(); add(1, 1, n, l, r, x); } else { if (type == 2) down(1, 1, n, l, r); else printf("%lld\n", sum(1, 1, n, l, r)); } } } return 0; }