题目链接:hdu-4027.
题目描述
一个长度为
n
n
n 的整数序列
a
1
,
a
2
,
.
.
.
a
n
a_{1},a_{2},...a_{n}
a1,a2,...an. 有
m
m
m个操作,每个操作为
s
i
,
l
i
,
r
i
s_{i}, l_{i},r_{i}
si,li,ri。
操作分为两种,当
s
i
s_{i}
si为
0
0
0时,将序列
a
a
a中区间
[
l
i
,
r
i
]
[l_{i},r_{i}]
[li,ri]中所有元素x更新为
x
\sqrt{x}
x; 当
s
i
s_{i}
si为
1
1
1时,对序列
a
a
a中区间
[
l
i
,
r
i
]
[l_{i},r_{i}]
[li,ri]中所有元素求和并输出。
序列
a
a
a 的元素和不超过
2
63
2^{63}
263.
思路
-
正确思路
- 求区间和很简单。
- 开方操作:因为每次操作都是开根号,对于一个数来讲,一直开根号到 1 1 1,再往后开根号始终是 1 1 1. 即使最大的数, 2 63 2^{63} 263只需要开 6 6 6次根号就会到 1 1 1. 所以,即使暴力将每个数都更新到 1 1 1,也不会有太多操作,每个数最多被更新几次,不过不同的区间叠加可能会使操作多几次。
- 精髓所在:如果待开方的某区间全为 1 1 1,不必再递归。
-
注意点:
① 通过提交式测试法,发现数组元素最小值为 1 1 1 ,所以终止的判断条件为 t [ i ] . s u m = = t [ i ] . r − t [ i ] . l + 1 t[i].sum == t[i].r - t[i].l + 1 t[i].sum==t[i].r−t[i].l+1. 如果有 0 0 0 的话,可以写 t [ i ] . s u m ≤ t [ i ] . r − t [ i ] . l + 1 t[i].sum \leq t[i].r - t[i].l + 1 t[i].sum≤t[i].r−t[i].l+1.
② 序列 a a a的元素值要用 l o n g   l o n g long\,long longlong.
③ 还有就是这个格式问题,每组数据之间有个空行。
其(wo)他(de)思路
- 发现最大值最多开 6 6 6次到 1 1 1之后,思路就停滞了,一直在想结点应该记录什么信息,能方便开方操作,其实啥也不用记录,直接更新到叶结点就完事了。
代码
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
const int MAXN = 100005;
LL a[MAXN];
struct node {
int l, r;
LL sum;
} t[MAXN * 4];
void push_up(int u) {
t[u].sum = t[lson(u)].sum + t[rson(u)].sum;
return;
}
void build(int l, int r, int u) {
t[u].l = l;
t[u].r = r;
if(l == r) {
t[u].sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(l, mid, lson(u));
build(mid+1, r, rson(u));
push_up(u);
return;
}
void update(int L, int R, int u) {
if(t[u].l == t[u].r) {
t[u].sum = sqrt(t[u].sum);
return;
}
if(t[u].sum <= t[u].r - t[u].l + 1) return; // *QQ*
int mid = (t[u].l + t[u].r) >> 1;
if(mid >= L) update(L, R, lson(u));
if(mid < R) update(L, R, rson(u));
push_up(u);
return;
}
LL Query(int L, int R, int u) {
if(L <= t[u].l && R >= t[u].r) {
return t[u].sum;
}
int mid = (t[u].l + t[u].r) >> 1;
LL sum = 0;
if(mid >= L) sum += Query(L, R, lson(u));
if(mid < R) sum += Query(L, R, rson(u));
return sum;
}
int main() {
int n, m, s, L, R;
int tt = 1;
while(scanf("%d", &n) != EOF) {
printf("Case #%d:\n",tt);
tt++;
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); // WA n
build(1,n,1);
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d%d",&s, &L, &R);
if(L > R) swap(L,R);
if(s == 0) update(L, R, 1);
else printf("%lld\n",Query(L, R, 1));
}
printf("\n"); // WA 2
}
return 0;
}
/*
2^63 6次
*/