zoukankan      html  css  js  c++  java
  • codevs 1081 线段树练习 2

    1081 线段树练习 2

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
    题目描述 Description

    给你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

    代码一:

    codevs 1081
    #include<cstdio>
    #include<iostream>
    
    using namespace std;
    int n,m;
    int sz[100010];
    struct node
    {
        int val,delta,l,r;
        node * cl,*cr;
     }* root=NULL;
    int sv(node * cur)
    {
        return cur?cur->val:0;
    }
    void down(node * cur)
    {
        if(cur->cl)
        {
            cur->cl->delta+=cur->delta;
            cur->cl->val+=cur->delta*(cur->cl->r-cur->cl->l+1);//叶节点是有用的,其余的区间是没用的 
        }
        if(cur->cr)
        {
            cur->cr->delta+=cur->delta;
            cur->cr->val+=cur->delta*(cur->cr->r-cur->cr->l+1);
        }
        cur->delta=0;
    }
    void build(node * &cur,int l,int r)
    {
        if(r<l)return;
        cur=new node;
        cur->l=l;cur->r=r;cur->delta=0;
        if(l==r)
        {
            cur->val=sz[l];
            cur->cl=cur->cr=NULL;
        }
        
        else
        {
            int mid=(l+r)/2;
            build(cur->cl,l,mid);
            build(cur->cr,mid+1,r);
            //不用更新当前的val,因为题目中没说要求区间的值 
        }
    }
    
    int query(node * cur,int pos)
    {
        if(cur->l==cur->r)return cur->val;
        if(cur->delta)down(cur);/**/
        int mid=(cur->l+cur->r)/2; 
        if(pos<=mid)return query(cur->cl,pos);/*一定是return,,否则就从最里面返回一个数,不会返回到主函数*/ 
        else return query(cur->cr,pos);
    }
    void add(node * cur,int l,int r,int delta)
    {
        if(l<=cur->l&&cur->r<=r)
        {
            cur->delta+=delta;/*记录当前区间欠这个区间内的每个数多少*/ 
            cur->val+=delta;//当cur是叶节点时,有用 
            return;
        }
        int mid=(cur->l+cur->r)/2;
        if(cur->delta)down(cur);/*如果要取这个区间的一部分加上delta的话,先把这个区间欠下面的数传下去,而不是先加上delta,因为这样直接加会把区间的其他部分多加了delta*/
        if(l<=mid)add(cur->cl,l,r,delta);
        if(mid<r)add(cur->cr,l,r,delta);
    }
    int main()
    {
        cin>>n;
        for(int j=1;j<=n;j++)scanf("%d",&sz[j]);
        build(root,1,n);
        cin>>m;
        for(int i=0;i<m;i++)
        {
            int a,b,c,d;
            scanf("%d",&a);
            if(a==1)
            {
                scanf("%d%d%d",&b,&c,&d);
                add(root,b,c,d);
            }
            else if(a==2)
            {
                scanf("%d",&b);
                printf("%d
    ",query(root,b));
            }
        }
        return 0;
    }
    teacher's

    代码二:

    #include<cstdio> 
    #include<iostream>
    using namespace std;
    #define INF 100001
    int sz[INF];
    struct node {
        int l,r,delta;
        node *child[2];
        int val;
    }*root=NULL;
    int n,q,a,b,c,x;
    void input()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        scanf("%d",&sz[i]);
    }
    void update(node *cur)
    {
        cur->val=cur->child[0]->val+cur->child[1]->val;
    }
    void bulid(node *&cur,int l,int r)
    {
        if(l>r) return ;
        cur=new node;
        cur->l=l;cur->r=r;
        cur->delta=0;
        if(l==r)
        {
            cur->child[0]=cur->child[1]=NULL;
            cur->val=sz[l];
        }
        else {
            int mid=(l+r)/2;
            bulid(cur->child[0],l,mid);
            bulid(cur->child[1],mid+1,r);
        //    update(cur);
        }
    }
    void down(node * cur)
    {
        if(cur->child[0])
        {
            cur->child[0]->delta+=cur->delta;
            cur->child[0]->val+=cur->delta*(cur->child[0]->r-cur->child[0]->l+1);
        }
        if(cur->child[1])
        {
            cur->child[1]->delta+=cur->delta;
            cur->child[1]->val+=cur->delta*(cur->child[1]->r-cur->child[1]->l+1);
        }
        cur->delta=0;
    }
    void add(node* cur,int l,int r,int delta)
    {
        if(cur->l>=l&&cur->r<=r)
        {
            cur->delta+=delta;
            cur->val+=delta*(cur->l-cur->r+1);
            return ;
        }
        int mid=(cur->l+cur->r)/2;
        if(cur->delta) down(cur);
        if(l<=mid) add(cur->child[0],l,r,delta);
        if(r>mid) add(cur->child[1],l,r,delta);
    }
    int query(node* cur,int x)
    {
        if(cur->l==cur->r)
        {
            return cur->val;
        }
        if(cur->delta) down(cur);
        int mid=(cur->l+cur->r)/2;
        if(x<=mid) return query(cur->child[0],x);
        else return query(cur->child[1],x);
    }
    int main()
    {
        input();
        bulid(root,1,n);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&x);
            if(x==1){
                scanf("%d%d%d",&a,&b,&c);
                add(root,a,b,c);
            } 
            else {
                scanf("%d",&a);
                printf("%d
    ",query(root,a));
            }
        }
        return 0;
    }
    mine
  • 相关阅读:
    POJ 2528 Mayor's posters(线段树+离散化)
    POJ 3468 A Simple Problem with Integers(线段树 成段增减+区间求和)
    HDU 1698 Just a Hook(线段树 区间替换)
    HDU 2795 Billboard(区间求最大值的位置update的操作在query里做了)
    JQuery中ajax使用方法
    JavaSe中JFrame和Frame的区别
    解决 Eclipse 项目有红感叹号的方法
    BaseServlet原理
    验证码的实现
    BaseServlet使用方法
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5318221.html
Copyright © 2011-2022 走看看