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?
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.
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;
}