• 线段树练习2


    题目传送:http://codevs.cn/problem/1081/

    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

    分类标签 Tags 

     代码

    #include<cstdio>
    #include<iostream>
    using namespace std;
    #define N 801000
    #define mid ((l+r)>>1)
    #define lc (k<<1)
    #define rc (k<<1|1)
    #define ll long long
    ll a[N],tag[N];
    ll read(){
        register ll f=1,x=0;
        register char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void ins(int k,int l,int r,int i,int val){
        if(l==r){a[k]=val;return;}
        if(i<=mid) ins(lc,l,mid,i,val);
        else ins(rc,mid+1,r,i,val);
        a[k]=a[lc]+a[rc];
    }
    void pushdown(int k,int l,int r){
        if(!tag[k]) return ;
        a[lc]+=tag[k]*(mid-l+1);
        a[rc]+=tag[k]*(r-mid);
        tag[lc]+=tag[k];tag[rc]+=tag[k];tag[k]=0;    
    }
    void add(int k,int l,int r,int x,int y,int val){
        if(l==x&&r==y){
            tag[k]+=val;a[k]+=(r-l+1)*val;return ;
        }
        pushdown(k,l,r);
        if(y<=mid) add(lc,l,mid,x,y,val);
        else if(x>mid) add(rc,mid+1,r,x,y,val);
        else add(lc,l,mid,x,mid,val),add(rc,mid+1,r,mid+1,y,val);
        a[k]=a[lc]+a[rc];
    }
    ll query(int k,int l,int r,int x,int y){
        if(l==x&&r==y) return a[k];
        pushdown(k,l,r);
        if(y<=mid) return query(lc,l,mid,x,y);
        else if(x>mid) return query(rc,mid+1,r,x,y);
        else return (query(lc,l,mid,x,mid)+query(rc,mid+1,r,mid+1,y));    
    }
    int main(){
        ll n=read(),b;
        for(ll i=1;i<=n;i++) b=read(),ins(1,1,n,i,b);
        ll m=read();
        for(ll i=1;i<=m;i++){
            ll opt=read();
            if(opt==1){
                ll l=read(),r=read(),val=read();
                add(1,1,n,l,r,val);
            }
            else{
                ll l=read();
                printf("%lld
    ",query(1,1,n,l,l));
            }
        }
        return 0;
    }
    #include<cstdio>
    struct node{
        int l,r,lch,rch,tage;
        long long sum;
    }tr[401000];
    int a[201000];
    int cnt;
    void build(int k,int l,int r){//不一样的建树 
        cnt++;
        tr[cnt].l=l;tr[cnt].r=r;
        if(l==r){
            tr[cnt].sum=a[l];return ;
        }
        tr[k].lch=cnt+1;
        int mid=(l+r)>>1;
        build(cnt+1,l,mid);
        tr[k].rch=cnt+1;
        build(cnt+1,mid+1,r);
        tr[k].sum=tr[tr[k].lch].sum+tr[tr[k].rch].sum;
    }
    void pushdown(int k){
        if(!tr[k].tage) return ;//下放--维护区 
        tr[tr[k].lch].sum+=tr[k].tage*(tr[tr[k].lch].r-tr[tr[k].lch].l+1);
        tr[tr[k].rch].sum+=tr[k].tage*(tr[tr[k].rch].r-tr[tr[k].rch].l+1);
        tr[tr[k].lch].tage+=tr[k].tage;
        tr[tr[k].rch].tage+=tr[k].tage;
        tr[k].tage=0;
    }
    void add(int k,int x,int y,int v){//在[l,r](初始是[1,n])中找到[x,y]修改 
        int l=tr[k].l,r=tr[k].r;
        if(l<=x&&r>=y){
            tr[k].sum+=(y-x+1)*v;
        }
        if(l==x&&r==y){
            tr[k].tage+=v;return ;
        }
        pushdown(k);
        int mid=(l+r)>>1;
        if(y<=mid) add(tr[k].lch,x,y,v);
        else if(x>mid) add(tr[k].rch,x,y,v);
        else add(tr[k].lch,x,mid,v),add(tr[k].rch,mid+1,y,v);    
    }
    long long query(int k,int x,int y){
        int l=tr[k].l,r=tr[k].r;
        if(l==x&&r==y) return tr[k].sum;
        pushdown(k);
        int mid=(l+r)>>1;
        if(y<=mid) return query(tr[k].lch,x,y);
        else if(x>mid) return query(tr[k].rch,x,y);
        else return query(tr[k].lch,x,mid)+query(tr[k].rch,mid+1,y);
    }
    int main(){int n,m,l,r,v,opt;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        build(1,1,n);
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d",&opt);
            if(opt==1){
                scanf("%d%d%d",&l,&r,&v);
                add(1,l,r,v);
            }
            if(opt==2){
                scanf("%d",&l);
                long long ans=query(1,l,l);
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }

    树状数组版本

    #include<cstdio>
    #include<iostream>
    #define lc k<<1
    #define rc k<<1|1
    using namespace std;
    inline int read(){
        register int x=0;bool f=1;
        register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    const int N=5e5+10;
    int n,m,a[N],c[N];
    inline int lowbit(int &x){
        return x&-x;
    }
    inline void updata(int p,int v){
        for(int i=p;i<=n;i+=lowbit(i)) c[i]+=v;
    }
    inline int query(int p){
        int res=0;
        for(int i=p;i;i-=lowbit(i)) res+=c[i];
        return res;
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++) updata(i,a[i]-a[i-1]);
        for(int i=1,opt,x,y,z;i<=m;i++){
            opt=read();
            if(opt==1){
                x=read();y=read();z=read();
                updata(x,z);
                updata(y+1,-z);
            } 
            else x=read(),printf("%d
    ",query(x));
        }
        return 0;
    }

     分块版

    /*
    如果我们把每m个元素分为一块,共有n/m块,每次区间加的操作会涉及O(n/m)个整块,以及区间两侧两个不完整的块中至多2m个元素。
    我们给每个块设置一个加法标记(就是记录这个块中元素一起加了多少),每次操作对每个整块直接O(1)标记,而不完整的块由于元素比较少,暴力修改元素的值。
    每次询问时返回元素的值加上其所在块的加法标记。
    这样每次操作的复杂度是O(n/m)+O(m),根据均值不等式,当m取√n时总复杂度最低,为了方便,我们都默认分块大小为√n
    */
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int F=501;
    int n,q,tag[F],block[F][F];
    int main(){
        scanf("%d",&n);
        int m=sqrt(n)+1;
        for(int i=0;i<n;i++) scanf("%d",&block[i/m][i%m]);
        scanf("%d",&q);
        for(int opt,x,y,z,b1,b2,p1,p2;q--;){
            scanf("%d",&opt);
            if(opt&1){
                scanf("%d%d%d",&x,&y,&z);x--;y--;
                b1=x/m;b2=y/m;
                p1=x%m;p2=y%m;
                if(b1==b2){
                    for(int j=p1;j<=p2;j++) block[b1][j]+=z;
                }
                else{
                    for(int j=p1;j<m;j++) block[b1][j]+=z;
                    for(int j=b1+1;j<b2;j++) tag[j]+=z;
                    for(int j=0;j<=p2;j++) block[b2][j]+=z;
                }
            }
            else{
                scanf("%d",&x);x--;
                b1=x/m;p1=x%m;
                printf("%d
    ",block[b1][p1]+tag[b1]);
            }
        }
        return 0;
    }
  • 相关阅读:
    Oracle Golden Gate
    DNS
    RMAN 管理
    黄伟-RAC生产库现场调整本分策略实战
    Linux下RAID技术
    OCP之黄伟 2
    About NULL Value
    OCP之黄伟
    Table
    Perl的简单变量
  • 原文地址:https://www.cnblogs.com/shenben/p/5459719.html
Copyright © 2020-2023  润新知