codevs 线段树练习ⅠⅡⅢ

1080 线段树练习

 

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
 
 
 
题目描述 Description

一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数m<10000条。

输入描述 Input Description

输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。

输出描述 Output Description

共m行,每个整数

样例输入 Sample Input

6

3

4

1 3 5

2 1 4

1 1 9

2 2 6

样例输出 Sample Output

22

22

数据范围及提示 Data Size & Hint

1≤N≤100000, m≤10000 。

 

 

#include <cstdio>
#include <iostream>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=1000005;
using namespace std;
int sum[maxn<<2];

void PushUP(int rt) 
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];//将两条小区间合并成一个大区间 
}

void build(int l,int r,int rt) 
{
    if (l==r)//最底层的节点 
    {
        scanf("%d",&sum[rt]);//读入节点的值 
        return;
    }
    int m=(l+r)>>1;//分成两个区间 
    build(lson);//分别搞搞左右两个区间 
    build(rson);
    PushUP(rt);//将最底层的节点的值传入上层节点 
}

void update(int p,int add,int l,int r,int rt) 
{
    if (l==r)//往最底层节点加上add 
    {
        sum[rt]+=add;
        return;
    }
    int m=(l+r)>>1;//取中间节点 
    if (p<=m)update(p,add,lson);//找到节点的儿子并且是p的祖先的节点,递归到p 
    else update(p,add,rson);
    PushUP(rt);//更新p祖先节点的值 
}

int query(int L,int R,int l,int r,int rt)//区间查询 
{//L,R是要查询的区间和,l、r是目前的区间,rt是目前的节点 
    if (L<=l&&r<=R) 
    {
        return sum[rt];//如果当前区间是所求区间的一部分,就加上这段区间 
    }
    int m=(l+r)>>1;//二分当前区间 
    int ret=0;//为所求区间的数值和 
    if (L<=m)ret+=query(L,R,lson);//加上所需区间 
    if (R>m)ret+=query(L,R,rson);
    return ret;
}

int main() 
{
    int n,m;
    scanf("%d",&n);//区间为1-n 
    build(1,n,1);//建树 
    int cz;
    cin>>m; 
    while(m--) 
    {
        scanf("%d",&cz); 
        int a,b;
        scanf("%d%d",&a,&b);
        if (cz==2)printf("%d\n",query(a,b,1,n,1));//query 询问区间的总值 
        //else if (cz==3)update(a,-b,1,n,1);//sub 往第a个数里减b 
        else update(a,b,1,n,1);//往第a个数中加b 
    }
    return 0;
}

 

 

给你N个数,有两种操作


1:给区间[a,b]的所有数都增加X


2:询问第i个数是什么?

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是1,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是2,后面跟1个整数i, 表示询问第i个位置的数是多少。

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 3

样例输出 Sample Output

5

数据范围及提示 Data Size & Hint

数据范围

1<=n<=100000

1<=q<=100000

 

 

#include <cstdio>
#include <iostream>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=1000005;
using namespace std;
int sum[maxn<<2];

void PushUP(int rt) 
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];//将两条小区间合并成一个大区间 
}

void build(int l,int r,int rt) 
{
    if (l==r)//最底层的节点 
    {
        scanf("%d",&sum[rt]);//读入节点的值 
        return;
    }
    int m=(l+r)>>1;//分成两个区间 
    build(lson);//分别搞搞左右两个区间 
    build(rson);
    PushUP(rt);//将最底层的节点的值传入上层节点 
}

void update(int p,int add,int l,int r,int rt) 
{
    if (l==r)//往最底层节点加上add 
    {
        sum[rt]+=add;
        return;
    }
    int m=(l+r)>>1;//取中间节点 
    if (p<=m)update(p,add,lson);//找到节点的儿子并且是p的祖先的节点,递归到p 
    else update(p,add,rson);
    PushUP(rt);//更新p祖先节点的值 
}

int query(int L,int R,int l,int r,int rt)//区间查询 
{//L,R是要查询的区间和,l、r是目前的区间,rt是目前的节点 
    if (L<=l&&r<=R) 
    {
        return sum[rt];//如果当前区间是所求区间的一部分,就加上这段区间 
    }
    int m=(l+r)>>1;//二分当前区间 
    int ret=0;//为所求区间的数值和 
    if (L<=m)ret+=query(L,R,lson);//加上所需区间 
    if (R>m)ret+=query(L,R,rson);
    return ret;
}

int main() 
{
    int n,m;
    scanf("%d",&n);//区间为1-n 
    build(1,n,1);//建树 
    int cz;
    cin>>m; 
    while(m--) 
    {
        scanf("%d",&cz); 
        int a,b,c;
        if (cz==1)
        {
            cin>>a>>b>>c;
            for(int i=a;i<=b;++i)
                update(i,c,1,n,1);
        }
        else 
        {
            cin>>a;
            cout<<query(a,a,1,n,1)<<endl;
        }
    }
    return 0;
}

 

 

 

题目描述 Description

给你N个数,有两种操作:


1:给区间[a,b]的所有数增加X


2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,

 

再接下来一个正整数Q,每行表示操作的个数,

 

如果第一个数是1,后接3个正整数,

 

表示在区间[a,b]内每个数增加X,如果是2,

 

表示操作2询问区间[a,b]的和是多少。

 

pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案

样例输入 Sample Input

3

1

2

3

2

1 2 3 2

2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000

1<=q<=200000

 
#include<cstdio>  
#include<cstring>
#include<iostream>  
#include<algorithm>  
using namespace std;  
#define N 500005  
#define lson l,m,rt<<1  
#define rson m+1,r,rt<<1|1  
#define ll long long  
ll sum[N*4];  
int visit[N*4];  
void pushUp(int rt)  
{  
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];  
}  

void build(int l,int r,int rt)  
{  
    visit[rt]=0;  
    if(l==r)  
    {  
        scanf("%lld",&sum[rt]);  
        return ;  
    }  
    int m=(l+r)>>1;  
    build(lson);  
    build(rson);  
    pushUp(rt);  
}  

void pushDown(int rt,int d)  
{  
    if(visit[rt]!=0)  
    {  
    
       visit[rt<<1]+=visit[rt];  
       visit[rt<<1|1]+=visit[rt];  
        sum[rt<<1|1]+=(ll)(d>>1)*visit[rt];
        sum[rt<<1]+=(ll)(d-(d>>1))*visit[rt];  
        visit[rt]=0;  
    }  
}  

void update(int L,int R,int c,int l,int r,int rt)  
{  
    if(L<=l && R>=r)  
    {  
        visit[rt]+=c;  
        sum[rt]+=(r-l+1)*c;  
        return ;  
    }  
    pushDown(rt,r-l+1);  
    int m=(l+r)>>1;  
    if(L<=m)  
        update(L,R,c,lson);  
    if(R>m)  
        update(L,R,c,rson);  
    pushUp(rt);  
}
  
ll query(int L,int R,int l,int r,int rt)  
{  
    if(L<=l&&R>=r)  
    {  
        return sum[rt];  
    }   
    pushDown(rt,r-l+1);  
    int m=(l+r)>>1;  
    ll ret=0;  
    if(L<=m)  
        ret+=query(L,R,lson);  
    if(R>m)  
        ret+=query(L,R,rson);  
    return ret;  
}  

int main()  
{  
    int n,q,a,b,c;  
    int s;  
    scanf("%d",&n);  
    build(1,n,1);
    cin>>q;  
    while(q--)  
    {  
        scanf("%d",&s);  
        if(s==1)  
        {  
            scanf("%d%d%d",&a,&b,&c);  
            update(a,b,c,1,n,1);  
        }  
        else if(s==2)  
        {  
            scanf("%d%d",&a,&b);  
            printf("%lld\n",query(a,b,1,n,1));  
        }  
    }  
    return 0;  
}

 

posted @ 2017-05-25 16:24  Grary  阅读(148)  评论(0编辑  收藏  举报
博客园 首页 私信博主 编辑 关注 管理 新世界