AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3038
线段树是我最不熟悉的东西之一,于是找几道题搞搞
这题就很简单了
有一个神奇的优化:
#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;
}