线段树练习3

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

1082 线段树练习 3

 

 时间限制: 3 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
 
 
 
题目描述 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

分类标签 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();
            if(l>r) swap(l,r);
            add(1,1,n,l,r,val);
        }
        else{
            ll l=read(),r=read();
            if(l>r) swap(l,r);
            printf("%lld\n",query(1,1,n,l,r));
        }
    }
    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){//数据上传(类似updata),更新父节点 
        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){//数据范围是long long 
    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%d",&l,&r);
            long long ans=query(1,l,r);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 最新版

#include<cstdio>
#include<iostream>
#define ll long long
#ifdef unix
#define LL "%lld"
#else
#define LL "%I64d"
#endif
#define lc k<<1
#define rc k<<1|1
using namespace std;
inline ll read(){
    register ll 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=2e5+10;
const int M=N<<2;
ll n,m,t1[N],a[M],tag[M];
void build(ll k,ll l,ll r){
    if(l==r){
        a[k]=t1[l];return ;
    }
    ll mid=l+r>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    a[k]=a[lc]+a[rc];
}
void pushdown(ll k,ll l,ll r){
    if(!tag[k]) return ;
    tag[lc]+=tag[k];
    tag[rc]+=tag[k];
    ll mid=l+r>>1;
    a[lc]+=tag[k]*(mid-l+1);
    a[rc]+=tag[k]*(r-mid);
    tag[k]=0;
}
void ins(ll k,ll l,ll r,ll x,ll y,ll val){
    if(l==x&&r==y){
        a[k]+=(y-x+1)*val;
        tag[k]+=val;
        return ;
    }
    pushdown(k,l,r);
    ll mid=l+r>>1;
    if(y<=mid) ins(lc,l,mid,x,y,val);
    else if(x>mid) ins(rc,mid+1,r,x,y,val);
    else ins(lc,l,mid,x,mid,val),ins(rc,mid+1,r,mid+1,y,val);
    a[k]=a[lc]+a[rc];
}
ll query(ll k,ll l,ll r,ll x,ll y){
    if(l==x&&r==y) return a[k];
    pushdown(k,l,r);
    ll mid=l+r>>1;
    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(){
    n=read();
    for(ll i=1;i<=n;i++) t1[i]=read();
    build(1,1,n);
    m=read();
    for(ll i=1,opt,x,y,z;i<=m;i++){
        opt=read();
        if(opt==1){
            x=read();y=read();z=read();
            ins(1,1,n,x,y,z);
        }
        else{
            x=read();y=read();
            printf(LL"\n",query(1,1,n,x,y));
        } 
    }
    return 0;
}

 可动态插点版

 

#include<cstdio>
using namespace std;
typedef long long ll;
int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 
    return x;
}
const int N=2e5+10;
const int M=N*4;
int n,a[N];
int root,sz,ls[M],rs[M],tag[M];
ll sum[M];
void updata(int k){
    sum[k]=sum[ls[k]]+sum[rs[k]];
}
void pushdown(int k,int l,int r){
    if(!tag[k]||l==r) return ;
    int mid=l+r>>1;
    tag[ls[k]]+=tag[k];
    tag[rs[k]]+=tag[k];
    sum[ls[k]]+=tag[k]*(mid-l+1);
    sum[rs[k]]+=tag[k]*(r-mid);
    tag[k]=0;
}
void build(int &k,int l,int r){
    if(!k) k=++sz;
    if(l==r){sum[k]=a[l];return ;}
    int mid=l+r>>1;
    build(ls[k],l,mid);
    build(rs[k],mid+1,r);
    updata(k);
}
void change(int k,int l,int r,int x,int y,int val){
    if(l==x&&r==y){
        tag[k]+=val;sum[k]+=(r-l+1)*val;return ;
    }
    pushdown(k,l,r);
    int mid=l+r>>1;
    if(y<=mid) change(ls[k],l,mid,x,y,val);
    else if(x>mid) change(rs[k],mid+1,r,x,y,val);
    else change(ls[k],l,mid,x,mid,val),change(rs[k],mid+1,r,mid+1,y,val);
    updata(k);
}
ll query(int k,int l,int r,int x,int y){
    if(l==x&&r==y) return sum[k];
    pushdown(k,l,r);
    int mid=l+r>>1;
    if(y<=mid) return query(ls[k],l,mid,x,y);
    else if(x>mid) return query(rs[k],mid+1,r,x,y);
    else return query(ls[k],l,mid,x,mid)+query(rs[k],mid+1,r,mid+1,y);
}
int main(){
    n=read();root=sz=1;//WA*1
    for(int i=1;i<=n;i++) a[i]=read();
    build(root,1,n);
    for(int cas=read();cas--;){
        int opt=read();
        if(opt==1){
            int l=read(),r=read(),val=read();
            change(root,1,n,l,r,val);
        }
        else{
            int l=read(),r=read();
            printf("%lld\n",query(root,1,n,l,r));
        }
    }
    return 0;
}

 分块版

#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int F=501;
int n,m,q;
ll ans,sum[F],tag[F],b[F][F];
int main(){
    n=read();
    int m=sqrt(n)+1;
    for(int i=0;i<n;i++) b[i/m][i%m]=read();
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            sum[i]+=b[i][j];
        }
    }
    q=read();
    for(int opt,x,y,z,b1,b2,p1,p2;q--;){
        opt=read();
        if(opt&1){
            x=read()-1;y=read()-1;z=read();
            b1=x/m;b2=y/m;
            p1=x%m;p2=y%m;
            if(b1==b2){
                for(int i=p1;i<=p2;i++) b[b1][i]+=z;
                sum[b1]+=(p2-p1+1)*z;
            }
            else{
                for(int i=p1;i<m;i++) b[b1][i]+=z;
                sum[b1]+=(m-p1)*z;
                for(int i=b1+1;i<b2;i++) tag[i]+=z;
                for(int i=0;i<=p2;i++) b[b2][i]+=z;
                sum[b2]+=(p2+1)*z;
            }
        }
        else{
            x=read()-1;y=read()-1;ans=0;
            b1=x/m;b2=y/m;
            p1=x%m;p2=y%m;
            if(b1==b2){
                for(int i=p1;i<=p2;i++) ans+=b[b1][i];
                ans+=(p2-p1+1)*tag[b1];
            }
            else{
                for(int i=p1;i<m;i++) ans+=b[b1][i];
                ans+=(m-p1)*tag[b1];
                for(int i=b1+1;i<b2;i++) ans+=sum[i]+tag[i]*m;
                for(int i=0;i<=p2;i++) ans+=b[b2][i];
                ans+=(p2+1)*tag[b2];
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 

posted @ 2016-05-04 20:47  神犇(shenben)  阅读(488)  评论(0编辑  收藏  举报