Can you answer these queries?
题意:
给一个序列,有俩种操作,一种是求区间和,一种是将区间每个数开根号后向下取整(QQ浏览器翻译成了四舍五入,坑了我很久)。
思路:
因为是对区间内的每个数开根号,没有办法用延迟更新,但是取根号在6,7次就会到1,所以如果父节点的权值等于r-l+1就不用往下跟新了,因为这个区间里每个数都是1,这样修改的复杂度就很低了总复杂度是
题目说的是对x到y进行操作,并没有说明x、y的大小关系,所以x可能会大于y,需要交换x、y
Code:
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
inline ll read() {
ll s = 0, w = 1;
char ch = getchar();
while (ch < 48 || ch > 57) {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= 48 && ch <= 57)
s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
ll tree[maxn<<2];
inline void build(int l,int r,int rt) {
if(l==r) {
tree[rt]=read();
return;
}
int mid=l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
inline void update(int x,int y,int l,int r,int rt) {
if(tree[rt]==r-l+1) return;
if(l==r) {
tree[rt]=sqrt(tree[rt]);
return;
}
int mid=l+r>>1;
if(x<=mid) update(x,y,l,mid,rt<<1);
if(y>mid) update(x,y,mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
inline ll query(int x,int y,int l,int r,int rt) {
if(x<=l&&r<=y) return tree[rt];
int mid=l+r>>1;
ll ans=0;
if(x<=mid) ans=query(x,y,l,mid,rt<<1);
if(y>mid) ans+=query(x,y,mid+1,r,rt<<1|1);
return ans;
}
int main() {
int n,m,t,x,y,cas=0;
while(~scanf("%d",&n)) {
build(1,n,1);
m=read();
printf("Case #%d:\n",++cas);
while(m--) {
t=read(),x=read(),y=read();
if(x>y) swap(x,y);
if(t) printf("%lld\n",query(x,y,1,n,1));
else update(x,y,1,n,1);
}
puts("");
}
return 0;
} [kuangbin带我飞]专题七 线段树 文章被收录于专栏
线段树入门到进阶 树不能只记得它的样子,要清楚它的性质,比如相邻点的关系
查看7道真题和解析