BZOJ 3211 花神游离各国 小清新线段树

花神游离各国

题目大意:给定长度为N的序列,支持区间开根,区间求和

样例

样例输入

4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
样例输出
101
11
11

题解:

平常的线段树维护标记非常麻烦

我们发现一个数多次开根后会是1或0,所以我们维护一个区间是否有需要修改的点,然后单点修改即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MAXN 100005
#define ll long long
using namespace std;
ll n,m,like[4*MAXN];
struct node{
	ll l,r,f,w,b;
}tree[4*MAXN];
void down(ll k){
	tree[k*2].w=tree[k*2+1].w=tree[k*2].f=tree[k*2+1].f=tree[k].f;
	tree[k].f=0;
}
void build(ll k,ll l,ll r){
	tree[k].l=l,tree[k].r=r;
	if(l==r){
		scanf("%lld",&like[k]);
		tree[k].w=tree[k].b=like[k];
		return ;
	}
	ll mid=(l+r)>>1;
	build(k*2,l,mid);
	build(k*2+1,mid+1,r);
	tree[k].w=tree[k*2].w+tree[k*2+1].w;
	tree[k].b=max(tree[k*2].b,tree[k*2+1].b);
}
ll get_sum(ll k,ll x,ll y){
	ll ans=0,mid=(tree[k].l+tree[k].r)>>1;
	if(tree[k].l>=x&&tree[k].r<=y)
		return tree[k].w;
	if(tree[k].f) down(k);
	if(x<=mid) ans+=get_sum(k*2,x,y);
	if(mid<y) ans+=get_sum(k*2+1,x,y);
	return ans;
}
void change(ll k,ll l,ll r){
	if(tree[k].b<=1) return ;
	if(tree[k].l==tree[k].r&&tree[k].w>1){
		tree[k].w=tree[k].f=(ll)sqrt(tree[k].w);
		tree[k].b=(ll)sqrt(tree[k].b);
		return ;
	}
	if(tree[k].f) down(k);
	ll mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid) change(k*2,l,r);
	if(mid<r) change(k*2+1,l,r);
	tree[k].w=tree[k*2].w+tree[k*2+1].w;
	tree[k].b=max(tree[k*2].b,tree[k*2+1].b);
}
int main(){
	scanf("%lld",&n);
	build(1,1,n);
	scanf("%lld",&m);
	for(ll i=1,opt,x,y;i<=m;i++){
		scanf("%lld%lld%lld",&opt,&x,&y);
		if(opt==1) printf("%lld\n",get_sum(1,x,y));
		if(opt==2) change(1,x,y);
	}
	return 0;
}

 

posted @ 2019-08-19 20:47  hzoi_xkl  阅读(85)  评论(0编辑  收藏  举报