【bzoj3038】上帝造题的七分钟2 线段树

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3038

线段树是我最不熟悉的东西之一,于是找几道题搞搞

这题就很简单了

有一个神奇的优化:

如果一个结点值为0或者1就不再更新;

如果一棵树左右儿子都不再更新,它也不再更新

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define MAXN 100010
#define FILE "read"
#define up(i,j,n) for(ll i=j;i<=n;i++)
#define dn(i,j,n) for(ll i=j;i>=n;i--)
namespace INIT{
	char buf[1<<15],*fs,*ft;
	inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
	inline ll read(){
		ll x=0,f=1;  char ch=getc();
		while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
		while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
		return x*f;
	}
}using namespace INIT;
ll n,m,a[MAXN],tr[MAXN<<2],vis[MAXN<<2];
void build(ll l,ll r,ll p){
	if(l>r)  return;
	if(l==r)  {tr[p]=a[l]; if(a[l]==0||a[l]==1) vis[p]=1; return;}
	ll mid=(l+r)>>1;
	build(l,mid,p<<1);  build(mid+1,r,p<<1|1);
	tr[p]=tr[p<<1]+tr[p<<1|1];
	vis[p]=vis[p<<1]&vis[p<<1|1];
}
void change(ll l,ll r,ll p,ll x,ll y){
	if(l>r)  return;
	if(vis[p])  return;
	if(l==r) {tr[p]=(ll)sqrt(tr[p]*1.0); if(tr[p]==0||tr[p]==1) vis[p]=1; return;}
	ll mid=(l+r)>>1;
	if(mid>=y)  change(l,mid,p<<1,x,y);
	else if(mid<x)  change(mid+1,r,p<<1|1,x,y);
	else{
		change(l,mid,p<<1,x,mid);
		change(mid+1,r,p<<1|1,mid+1,y);
	}
	tr[p]=tr[p<<1]+tr[p<<1|1];
	vis[p]=vis[p<<1]&vis[p<<1|1];
}
ll ask(ll l,ll r,ll p,ll x,ll y){
	if(x>r||y<l)  return 0;
	if(x<=l&&y>=r)  return tr[p];
	ll mid=(l+r)>>1;
	return ask(l,mid,p<<1,x,y)+ask(mid+1,r,p<<1|1,x,y);
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	n=read();
	up(i,1,n)  a[i]=read();
	build(1,n,1);
	m=read();
	up(i,1,m){
		ll flag=read(),x=read(),y=read();
		if(x>y)  swap(x,y);
		if(flag==0) change(1,n,1,x,y);
		else printf("%lld\n",ask(1,n,1,x,y));
	}
	return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值