您的位置:首页 > 产品设计 > UI/UE

hdu4027 Can you answer these queries?(线段树)

2017-08-23 13:52 483 查看
题目链接:点击链接

题意:

有n个数,现在有一种操作,将这n个数中的一个区间[x, y],每个数都开平方。询问区间的和。

思路:

建树的时候,当前节点保存了对应区间的和。更新的时候,若当前节点对应的区间为[l, r],如果区间和小于(r-l+1),不往下更新,反之往下更新。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

const int maxn = 100000 + 10;
typedef long long ll;
ll tree[maxn<<2];

void pushup(int rt){
tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}

void build(int rt, int l, int r){
if(l==r){
scanf("%lld", &tree[rt]);
}
else{
int mid = (l+r) / 2;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
pushup(rt);
}
}

void update(int rt, int a, int b, int l, int r){
int mid = (l+r)>>1;
if(a<=l && r<=b){
if(l==r){
tree[rt] = (ll)sqrt(tree[rt]);
return;
}
if(tree[rt]>(r-l+1)){
if(a <= mid) update(rt<<1, a, b, l, mid);
if(mid < b) update(rt<<1|1, a, b, mid+1, r);
pushup(rt);
}
}
else{
if(a <= mid) update(rt<<1, a, b, l, mid);
if(mid < b) update(rt<<1|1, a, b, mid+1, r);
pushup(rt);
}
}

ll query(int rt, int a, int b, int l, int r){
if(a<=l && r<=b){
return tree[rt];
}
else{
int mid = (l+r)>>1;
ll ans = 0;
if(a<=mid) ans += query(rt<<1, a, b, l, mid);
if(mid<b) ans += query(rt<<1|1, a, b, mid+1, r);
return ans;
}
}

int main(){
int n, q, opt, a, b, Case=0;
while(scanf("%d", &n)!=EOF){
build(1, 1, n);
scanf("%d", &q);
printf("Case #%d:\n", ++Case);
for(int i=0; i<q; ++i){
scanf("%d%d%d", &opt, &a, &b);
if(opt==0){
if(a>b) swap(a, b);
update(1, a, b, 1, n);
}
if(opt==1){
if(a>b) swap(a, b);
printf("%lld\n", query(1, a, b, 1, n));
}
}
printf("\n");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: