本文主要是介绍Codevs 1082 线段树练习 3(线段树分块),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1082 线段树练习 3
时间限制: 3 s
空间限制: 128000 KB
题目等级 : 大师 Maste
传送门
题目描述 Description
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
输出描述 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<iostream>
#include<cstdio>
#define MAXN 200001
#define ll long long
using namespace std;
ll n,m,tot,cut,aa[MAXN+10];
struct data
{int l,r;int lc,rc;ll sum;ll bj;
}tree[MAXN*4];
void build(int l,int r)
{int k=++cut;tree[k].l=l;tree[k].r=r;if(l==r){tree[k].sum=aa[l];return ;}int mid=(l+r)>>1;tree[k].lc=cut+1;build(l,mid);tree[k].rc=cut+1;build(mid+1,r);tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
}
void updata(int k)
{tree[tree[k].lc].sum+=tree[k].bj*(tree[tree[k].lc].r-tree[tree[k].lc].l+1);tree[tree[k].rc].sum+=tree[k].bj*(tree[tree[k].rc].r-tree[tree[k].rc].l+1);tree[tree[k].lc].bj+=tree[k].bj;tree[tree[k].rc].bj+=tree[k].bj;tree[k].bj=0;
}
void add(int k,int l,int r,int add1)
{if(l<=tree[k].l&&tree[k].r<=r){tree[k].bj+=add1;tree[k].sum+=add1*(tree[k].r-tree[k].l+1);return ;}if(tree[k].bj) updata(k);int mid=(tree[k].l+tree[k].r)>>1;if(l<=mid) add(tree[k].lc,l,r,add1);if(r>mid) add(tree[k].rc,l,r,add1);tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
}
ll query(int k,int l,int r)
{if(l<=tree[k].l&&tree[k].r<=r) return tree[k].sum;ll tot=0;if(tree[k].bj) updata(k);int mid=(tree[k].l+tree[k].r)>>1;if(l<=mid) tot+=query(tree[k].lc,l,r);if(r>mid) tot+=query(tree[k].rc,l,r);tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;return tot;
}
int main()
{int x,a,b,add1;cin>>n;for(int i=1;i<=n;i++){cin>>aa[i];}build(1,n);cin>>m;for(int i=1;i<=m;i++){scanf("%d",&x);if(x==1){scanf("%d %d %d",&a,&b,&add1);add(1,a,b,add1);}else{scanf("%d %d",&a,&b);printf("%lld\n",query(1,a,b));}}return 0;
}
/*
分块.
区间修改 区间查询.
这题并没有1A orz.
error:不完整的块修改忘记维护sum了 然后这题要long long.
修改贡献为addval*size.(size不一定是m,可能不完整 其实也无所谓...
*/
#include<cstdio>
#include<cmath>
#include<iostream>
#define MAXN 200001
#define LL long long
using namespace std;
int n,m,q,s[MAXN],belong[MAXN],sum[MAXN],tag[MAXN],size[MAXN];
LL ans;
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-48,ch=getchar();return x*f;
}
void slovechange(int x,int y,int z)
{for(int i=x;i<=min(y,belong[x]*m);i++) s[i]+=z,sum[belong[i]]+=z;for(int i=belong[x]+1;i<=belong[y]-1;i++) sum[i]+=z*size[i],tag[i]+=z;if(belong[x]!=belong[y])for(int i=(belong[y]-1)*m+1;i<=y;i++) s[i]+=z,sum[belong[i]]+=z;return ;
}
LL slovequery(int x,int y)
{ans=0;for(int i=x;i<=min(y,belong[x]*m);i++) ans+=s[i]+tag[belong[i]];for(int i=belong[x]+1;i<=belong[y]-1;i++) ans+=sum[i];if(belong[x]!=belong[y])for(int i=(belong[y]-1)*m+1;i<=y;i++) ans+=s[i]+tag[belong[i]];return ans;
}
int main()
{int x,y,z,k;n=read();m=sqrt(n);for(int i=1;i<=n;i++) belong[i]=(i-1)/m+1,size[belong[i]]=m;size[belong[n]]=n-(belong[n-1]*size[belong[n-1]]);for(int i=1;i<=n;i++) s[i]=read(),sum[belong[i]]+=s[i];q=read();while(q--){z=read();if(z&1) x=read(),y=read(),z=read(),slovechange(x,y,z);else x=read(),y=read(),printf("%lld\n",slovequery(x,y));}return 0;
}
这篇关于Codevs 1082 线段树练习 3(线段树分块)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!