HDU-4027(线段树)

HDU - 4027 The 36th ACM/ICPC Asia Regional Shanghai Site

    • 题目描述
    • 思路
    • 代码

题目链接:hdu-4027.

题目描述

一个长度为 n n n 的整数序列 a 1 , a 2 , . . . a n a_{1},a_{2},...a_{n} a1,a2,...an. 有 m m m个操作,每个操作为 s i , l i , r i s_{i}, l_{i},r_{i} si,li,ri
操作分为两种,当 s i s_{i} si 0 0 0时,将序列 a a a中区间 [ l i , r i ] [l_{i},r_{i}] [li,ri]中所有元素x更新为 x \sqrt{x} x ; 当 s i s_{i} si 1 1 1时,对序列 a a a中区间 [ l i , r i ] [l_{i},r_{i}] [li,ri]中所有元素求和并输出。
序列 a a a 的元素和不超过 2 63 2^{63} 263.

思路

正确思路
求区间和很简单。
开方操作:因为每次操作都是开根号,对于一个数来讲,一直开根号到 1 1 1,再往后开根号始终是 1 1 1. 即使最大的数, 2 63 2^{63} 263只需要开 6 6 6次根号就会到 1 1 1. 所以,即使暴力将每个数都更新到 1 1 1,也不会有太多操作,每个数最多被更新几次,不过不同的区间叠加可能会使操作多几次。
精髓所在:如果待开方的某区间全为 1 1 1,不必再递归。
注意点:
① 通过提交式测试法,发现数组元素最小值为 1 1 1 ,所以终止的判断条件为 t [ i ] . s u m = = t [ i ] . r − t [ i ] . l + 1 t[i].sum == t[i].r - t[i].l + 1 t[i].sum==t[i].rt[i].l+1. 如果有 0 0 0 的话,可以写 t [ i ] . s u m ≤ t [ i ] . r − t [ i ] . l + 1 t[i].sum \leq t[i].r - t[i].l + 1 t[i].sumt[i].rt[i].l+1.
② 序列 a a a的元素值要用 l o n g   l o n g long\,long longlong.
③ 还有就是这个格式问题,每组数据之间有个空行。
其(wo)他(de)思路
发现最大值最多开 6 6 6次到 1 1 1之后,思路就停滞了,一直在想结点应该记录什么信息,能方便开方操作,其实啥也不用记录,直接更新到叶结点就完事了。

代码

#include 

using namespace std;
#define LL long long
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)

const int MAXN = 100005;

LL a[MAXN];
struct node {
    int l, r;
    LL sum;
} t[MAXN * 4];
void push_up(int u) {
    t[u].sum = t[lson(u)].sum + t[rson(u)].sum;
    return;
}
void build(int l, int r, int u) {
    t[u].l = l;
    t[u].r = r;
    if(l == r) {
        t[u].sum = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, lson(u));
    build(mid+1, r, rson(u));
    push_up(u);
    return;
}
void update(int L, int R, int u) {
    if(t[u].l == t[u].r) {
        t[u].sum = sqrt(t[u].sum);
        return;
    }
    if(t[u].sum <= t[u].r - t[u].l + 1) return; // *QQ*
    int mid = (t[u].l + t[u].r) >> 1;
    if(mid >= L) update(L, R, lson(u));
    if(mid < R) update(L, R, rson(u));
    push_up(u);
    return;
}
LL Query(int L, int R, int u) {
    if(L <= t[u].l && R >= t[u].r) {
        return t[u].sum;
    }
    int mid = (t[u].l + t[u].r) >> 1;
    LL sum = 0;
    if(mid >= L) sum += Query(L, R, lson(u));
    if(mid < R) sum += Query(L, R, rson(u));
    return sum;
}
int main() {
    int n, m, s, L, R;
    int tt = 1;
    while(scanf("%d", &n) != EOF) {
        printf("Case #%d:\n",tt);
        tt++;
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); // WA n 
        build(1,n,1);
        scanf("%d", &m);
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d",&s, &L, &R);
            if(L > R) swap(L,R);
            if(s == 0) update(L, R, 1);
            else printf("%lld\n",Query(L, R, 1));
        }
        printf("\n"); // WA 2
    }    
    return 0;    
}
/*
2^63  6次 
*/

你可能感兴趣的:(数据结构-线段树)