P4145 根号线段树
上帝造题的七分钟 2 / 花神游历各国
输入格式
第一行一个整数 \(n\),代表数列中数的个数。
第二行 \(n\) 个正整数,表示初始状态下数列中的数。
第三行一个整数 \(m\),表示有 \(m\) 次操作。
接下来 \(m\) 行每行三个整数 k l r
。
-
\(k=0\) 表示给 \([l,r]\) 中的每个数开平方(下取整)。
-
\(k=1\) 表示询问 \([l,r]\) 中各个数的和。
数据中有可能 \(l>r\),所以遇到这种情况请交换 \(l\) 和 \(r\)。
输出格式
对于询问操作,每行输出一个回答。
样例 #1
样例输入 #1
10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8
样例输出 #1
19
7
6
提示
对于 \(30\%\) 的数据,\(1\le n,m\le 10^3\),数列中的数不超过 \(32767\)。
对于 \(100\%\) 的数据,\(1\le n,m\le 10^5\),\(1\le l,r\le n\),数列中的数大于 \(0\),且不超过 \(10^{12}\)。
由于是根号操作 只能逐点修改 所以没有pushdown了
维护一个 tr[p].maxx 当 maxx<=1时 取根号不影响值 直接return
只用修改 maxx>1的 只需要很少的操作便能都取到 1/0 所以很高效
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n,m,a[N];
struct SegTree {
int l,r,sum,maxx;
} tr[N<<2];
void pushup(int p) {
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
tr[p].maxx=max(tr[p<<1].maxx,tr[p<<1|1].maxx);
}
void build(int p,int l,int r) {
tr[p].l=l,tr[p].r=r;
if(l==r) {
tr[p].maxx=tr[p].sum=a[l];
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r) {
if(tr[p].maxx<=1)return ;
if(tr[p].l==tr[p].r) {
tr[p].maxx=tr[p].sum=sqrt(tr[p].maxx);
return ;
}
int mid=(tr[p].l+tr[p].r)>>1;
if(l<=mid)modify(p<<1,l,r);
if(r>mid)modify(p<<1|1,l,r);
pushup(p);
}
int query(int p,int l,int r) {
int sum=0;
if(l<=tr[p].l&&tr[p].r<=r)return tr[p].sum;
int mid=(tr[p].l+tr[p].r)>>1;
if(l<=mid)sum+=query(p<<1,l,r);
if(r>mid)sum+=query(p<<1|1,l,r);
return sum;
}
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i];
build(1,1,n);
cin>>m;
for(int i=1; i<=m; i++) {
int k,l,r;
cin>>k>>l>>r;
if(l>r)swap(l,r);
if(k==0)modify(1,l,r);
if(k==1)cout<<query(1,l,r)<<"\n";
}
return 0;
}