UESTC 1073 秋实大哥与线段树 线段树&&改值与区间和 or 树状数组

秋实大哥与线段树

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit  Status

“学习本无底,前进莫徬徨。” 秋实大哥对一旁玩手机的学弟说道。

秋实大哥是一个爱学习的人,今天他刚刚学习了线段树这个数据结构。

为了检验自己的掌握程度,秋实大哥给自己出了一个题,同时邀请大家一起来作。

秋实大哥的题目要求你维护一个序列,支持两种操作:一种是修改某一个元素的值;一种是询问一段区间的和。

Input

第一行包含一个整数 n ,表示序列的长度。

接下来一行包含 n 个整数 ai ,表示序列初始的元素。

接下来一行包含一个整数 m m,表示操作数。

接下来 m m行,每行是以下两种操作之一:

1 x v : 表示将第x个元素的值改为v
2 l r : 表示询问[l,r]这个区间的元素和

1nmvai100000  1lrn      

Output

对于每一个 2   l     操作,输出一个整数占一行,表示对应的答案。

Sample input and output

Sample Input Sample Output
3
1 2 3
3
2 1 2
1 1 5
2 1 2
3
7

Source

2015 UESTC Training for Data Structures
The question is from   here.

My Solution

注意数据溢出  n <= 1e5, ai <= 1e5 ,则 sum[i] <= 1e10; 一百亿了用 int 明显溢出了

1、建树的时候 用 Modify,即直接用改值函数

#include <iostream>
#include <cstdio>
#include <cstring>
typedef long long LL;
using namespace std;
const int maxn = 1<<(20);

LL sum[maxn];
int size;
LL _Query(int a,int b,int l,int r,int Ind){
    if(a <= l && b >= r) return sum[Ind];
    int mid = (l+r)>>1; LL ret = 0;
    if(a <= mid) ret = ret + _Query(a,b,l,mid,Ind<<1);
    if(b > mid) ret = ret + _Query(a,b,mid+1,r,(Ind<<1)+1);
    return ret;
}

void _Modify(int a,int l,int r,int Ind,int d){
    if(l == r && l == a){
        sum[Ind] = d;
        return;
    }
    int mid = (l+r)>>1;
    if(a <= mid) _Modify(a,l,mid,Ind<<1,d);
    else _Modify(a,mid+1,r,(Ind<<1)+1,d);
    sum[Ind] = sum[Ind<<1] + sum[(Ind<<1)+1];
}

LL Query(int a,int b) {return _Query(a,b,1,size,1);}
void Modify(int a,int d){return _Modify(a,1,size,1,d);}

int main()
{
    #ifdef LOCAL
    freopen("a.txt", "r", stdin);
    #endif // LOCAL

    int  n,v;
    scanf("%d", &n); size = n;
    for(int i = 1; i <= size; i++){
        scanf("%d", &v);
        Modify(i,v);
    }
    int m, x, y, z;
    scanf("%d", &m);
    while(m--){
        scanf("%d%d%d", &x, &y, &z);
        if(x == 1) Modify(y,z);
        else printf("%lld\n", Query(y,z));
    }
    return 0;
}


2、建树的时候 用 改版的Modify放入,最后一个的时候,再返回并维护好每个节点的信息;

#include <iostream>
#include <cstdio>
#include <cstring>
typedef long long LL;
using namespace std;
const int maxn = 1<<(20);

LL sum[maxn];
int size;
LL _Query(int a,int b,int l,int r,int Ind){
    if(a <= l && b >= r) return sum[Ind];
    int mid = (l+r)>>1; LL ret = 0;
    if(a <= mid) ret = ret + _Query(a,b,l,mid,Ind<<1);
    if(b > mid) ret = ret + _Query(a,b,mid+1,r,(Ind<<1)+1);
    return ret;
}

void _Modify(int a,int l,int r,int Ind,int d){
    if(l == r && l == a){
        sum[Ind] = d;
        return;
    }
    int mid = (l+r)>>1;
    if(a <= mid) _Modify(a,l,mid,Ind<<1,d);
    else _Modify(a,mid+1,r,(Ind<<1)+1,d);
    sum[Ind] = sum[Ind<<1] + sum[(Ind<<1)+1];
}

void _Build(int a,int l,int r,int Ind,int d){
    if(l == r && l == a){
        sum[Ind] = d;
        return;
    }
    int mid = (l+r)>>1;
    if(a <= mid) _Modify(a,l,mid,Ind<<1,d);
    else _Modify(a,mid+1,r,(Ind<<1)+1,d);
    //sum[Ind] = sum[Ind<<1] + sum[(Ind<<1)+1];
}

LL Query(int a,int b) {return _Query(a,b,1,size,1);}
void Modify(int a,int d){return _Modify(a,1,size,1,d);}
void Build(int a,int d){return _Build(a,1,size,1,d);}

int main()
{
    #ifdef LOCAL
    freopen("a.txt", "r", stdin);
    #endif // LOCAL

    int  v;
    scanf("%d", &size);
    for(int i = 1; i <= size; i++){
        scanf("%d", &v);
        if(i!=size) Build(i,v);
        else Modify(i,v);
    }
    int m, x, y, z;
    scanf("%d", &m);
    while(m--){
        scanf("%d%d%d", &x, &y, &z);
        if(x == 1) Modify(y,z);
        else printf("%lld\n", Query(y,z));
    }
    return 0;
}


3、建树的时候必定还可以更快一点,嘿嘿☺☺但不会

4、树状数组,题目故意的,这个题目最适合的方法应该是用树状数组了☺

Thank you!

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