【SPOJ】Can you answer these queries IV【线段树】

来源:互联网 发布:win10防火墙设置21端口 编辑:程序博客网 时间:2024/06/06 00:25

题意:给出一个数列,m次操作,可以把其中一段区间的数字开方,或者询问一段区间的和。

思路:线段树的点修改区间询问,由于是对一个数字进行开方,因而暴力点修改就行,这里的优化是记录一段区间是否是连续的1,是的话就不需要再继续修改下去。

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;#define N 100005#define mid (l+r>>1)#define lc (d<<1)#define rc (d<<1|1)typedef long long ll;struct Tr{    ll sum;}tr[N<<2];void Push(int d) {    tr[d].sum = tr[lc].sum+tr[rc].sum;}void build(int d, int l, int r) {    if (l == r) {        scanf("%lld", &tr[d].sum);        return;    }    build(lc, l, mid);    build(rc, mid+1, r);    Push(d);}ll query(int d, int l, int r, int L, int R) {    if (l == L && R == r) {        return tr[d].sum;    }    if (R <= mid) return query(lc, l, mid, L, R);    else if (L > mid) return query(rc, mid+1, r, L, R);    else return query(lc, l, mid, L, mid)+query(rc, mid+1, r, mid+1, R);}void update(int d, int l, int r, int L, int R) {    if (tr[d].sum == 1ll*(r-l+1)) return;    if (l == r) {        tr[d].sum = 1ll*sqrt(tr[d].sum*1.0);        return;    }    if (R <= mid) update(lc, l, mid, L, R);    else if (L > mid) update(rc, mid+1, r, L, R);    else update(lc, l, mid, L, mid), update(rc, mid+1, r, mid+1, R);    Push(d);}int main() {    int n, m, j, l, r, ca = 1;    while (~scanf("%d", &n)) {        build(1, 1, n);        scanf("%d", &m);        printf("Case #%d:\n", ca++);        while (m--) {            scanf("%d%d%d", &j, &l, &r);            if (l > r) swap(l, r);            if (j) printf("%lld\n", query(1, 1, n, l, r));            else update(1, 1, n, l, r);        }        puts("");    }}


0 0
原创粉丝点击