线段树——H - 花神游历各国
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4 1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
Hint
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
ps:1:ret和sum开始没longlong;
2:开平方需要标记,最多几次后就开方就没得用了
3:因为卡时间所以还是不要用cin和cout,我开始就是这个超时
4:ios::sync_with_stdio(false);这个可以优化输入cin,但此时不能再有scanf
5:注意看题。
代码:
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
#define N 410000//4倍
ll sum[N];//longlong存
int a[N],vis[N];
void build(int l,int r,int rt){
if(l==r) {
sum[rt]=a[l];
if(sum[rt]<=1)//判断
vis[rt]=1;
return ;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
sum[rt]=sum[rt*2]+sum[rt*2+1];
vis[rt]=(vis[rt*2]&vis[rt*2+1]);
}
ll query(int l1,int r1,int l,int r,int rt){
if(l1<=l&&r1>=r) return sum[rt];
int mid=(l+r)/2;
ll ret=0;
if(l1<=mid) {
ret+=query(l1,r1,l,mid,rt*2);
}
if(r1>mid){
ret+=query(l1,r1,mid+1,r,rt*2+1);
}
return ret;
}
void update(int l1,int r1,int l,int r,int rt){
if(vis[rt]==1) return;
if(l==r){//这里是开方,和前几个题不一样,这个是每个开,不是整体上开
a[l]=(int)(sqrt(a[l]));//由单个的被开方递归到整体
sum[rt]=(ll)(a[l]);
if(a[l]<=1) vis[rt]=1;
return ;
}
int mid=(l+r)/2;
if(l1<=mid){
update(l1,r1,l,mid,rt*2);
}
if(r1>mid){
update(l1,r1,mid+1,r,rt*2+1);
}
sum[rt]=sum[rt*2]+sum[rt*2+1];
vis[rt]=(vis[rt*2]&vis[rt*2+1]);
}
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,n,1);
int m;
cin>>m;
while(m--){
int a,b,c;
cin>>a>>b>>c;
if(a==1){
ll ans=query(b,c,1,n,1);
printf("%lld\n",ans);
}
if(a==2){
update(b,c,1,n,1);
}
}
return 0;
}