线段树——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
",ans);
        }
        if(a==2){
            update(b,c,1,n,1);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/skyleafcoder/p/12319552.html