给定长度为
的
数组,执行两种操作:
-
区间根号:将
这个区间中的全部元素修改为其开根号后的值,即
-
区间和查询:输出下标在
这个区间中的所有元素之和,即
维护区间开根号十分困难,但是仔细想会知道开根号的次数不会超过5次(
连续开根号
次就变成
了,即使是
级别,连续开根号
次就变成
了)
所以需要维护区间的最大值,如果这个区间的最大值是
,那么这个区间就不需要再执行操作
了,直接跳过。如果不为
,就直接暴力循环区间将每一个数开根号。最多只会修改
次,其中
是一个很小的常数。
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 1e5 + 10;
struct Node{
int l, r;
int sum, Max;
}tr[4 * N];
int n, m, a[N];
void push_up(int u){
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
tr[u].Max = max(tr[u << 1].Max, tr[u << 1 | 1].Max);
}
void build(int u, int l, int r){
if(l == r) tr[u] = {l, r, a[l], a[l]};
else{
tr[u] = {l, r, 0, 0};
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
push_up(u);
}
}
void modify_sqrt(int u, int pos){
if(tr[u].l == pos && pos == tr[u].r){
tr[u].sum = sqrt(tr[u].sum);
tr[u].Max = sqrt(tr[u].Max);
return ;
}
else{
int mid = (tr[u].l + tr[u].r) >> 1;
if(pos <= mid) modify_sqrt(u << 1, pos);
else modify_sqrt(u << 1 | 1, pos);
push_up(u);
}
}
void modify(int u, int l, int r){
if(l <= tr[u].l && tr[u].r <= r){
if(tr[u].Max != 1){
for(int i = tr[u].l; i <= tr[u].r; i ++){
modify_sqrt(1, i);
}
}
return ;
}
else{
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) modify(u << 1, l, r);
if(r > mid) modify(u << 1 | 1, l, r);
push_up(u);
}
}
int query(int u, int l, int r){
if(l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
else{
int sum = 0;
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid) sum += query(u << 1, l, r);
if(r > mid) sum += query(u << 1 | 1, l, r);
return sum;
}
}
signed main(){
HelloWorld;
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> a[i];
build(1, 1, n);
while(m --){
int op; cin >> op;
if(op == 1){
int l, r; cin >> l >> r;
modify(1, l, r);
}
if(op == 2){
int l, r; cin >> l >> r;
cout << query(1, l, r) << endl;
}
}
return 0;
}



京公网安备 11010502036488号