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;
}
posted @ 2023-04-26 21:58  N0zoM1z0  阅读(15)  评论(0编辑  收藏  举报