【题目描述】
花神喜欢步行游历各国,顺便虐爆各地竞赛。花神有一条游览路线,它是线型的,也就是说,所有游历国家呈一条线的形状排列,花神对每个国家都有一个喜欢程度(当然花神并不一定喜欢所有国家)。
每一次旅行中,花神会选择一条旅游路线,它在那一串国家中是连续的一段,这次旅行带来的开心值是这些国家的喜欢度的总和,当然花神对这些国家的喜欢程序并不是恒定的,有时会突然对某些国家产生反感,使他对这些国家的喜欢度变为 (可能是花神虐爆了那些国家的 OI,从而感到乏味)。
现在给出花神每次的旅行路线,以及开心度的变化,请求出花神每次旅行的开心值。
【Input】
第一行是一个整数 NN,表示有 NN 个国家;
第二行有 NN 个空格隔开的整数,表示每个国家的初始喜欢度;
第三行是一个整数 MM,表示有 MM 条信息要处理;
第四行到最后,每行三个整数 x,l,rx,l,r,当 x = 1时询问游历国家 ll 到 rr 的开心值总和,就是 ,当 x = 2 时国家 ll 到 rr 中每个国家的喜欢度变为 。
【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
【Data range & Tips】
对于全部数据,
注:建议使用 sqrt 函数,且向下取整。
【Solution】
没跑满,然后过了(神奇)!
区间修改时不打懒标记,把区间内每个叶子节点都遍历(我不知道开根号怎么打懒标记)
然后有个小优化:
维护maxn记录当前区间最大的数,因为1,0开方和原值一样,所以当时就return;
【Code】
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
struct Segment_Tree{long long sum,maxn;
}tree[1000000];
int n,m,a[100100],op,ll,rr;
inline void build(int k,int l,int r){if(l==r){tree[k].sum=a[l];tree[k].maxn=a[l];return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;tree[k].maxn=max(tree[k<<1].maxn,tree[k<<1|1].maxn);
}
inline void modify(int k,int l,int r,int x,int y){if(l>y||r<x)return;if(tree[k].maxn<=1)return;if(l==r){tree[k].sum=floor(sqrt(tree[k].sum));tree[k].maxn=tree[k].sum;return;}int mid=(l+r)>>1;if(x<=mid)modify(k<<1,l,mid,x,y);if(y>mid)modify(k<<1|1,mid+1,r,x,y);tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;tree[k].maxn=max(tree[k<<1].maxn,tree[k<<1|1].maxn);
}
inline long long Ask(int k,int l,int r,int x,int y){if(l>y||r<x)return 0;if(l>=x&&r<=y)return tree[k].sum;int mid=(l+r)>>1;long long res=0;if(x<=mid)res+=Ask(k<<1,l,mid,x,y);if(y>mid)res+=Ask(k<<1|1,mid+1,r,x,y);return res;
}
int main(){scanf("%d",&n);for(register int i=1;i<=n;i++)scanf("%d",&a[i]);build(1,1,n);scanf("%d",&m);for(register int i=1;i<=m;i++){scanf("%d%d%d",&op,&ll,&rr);if(op==1){printf("%lld\n",Ask(1,1,n,ll,rr)); }else{modify(1,1,n,ll,rr);}}return 0;
}