题目:
题目链接:
POJ A Simple Problem with Integers
题解:洛谷上的线段树的模板1,写这个也就是用来复习一下的,,,毕竟学这个的时候就是半年前了,然后就对着这个板子敲了三四遍才记起来,,,放一下模板一吧,,LUOGU 线段树模板一
线段树学习博客推荐:超全的线段树总结
这里就来根据jyl大神给我的金玉良言进行对于一般数据结构的做法进行个总结:
(前方仅个人理解,若有不同见解,欢迎评论!)
分块的复杂度是O(nsqrtn)的,线段树是O(nlogn),树状数组的复杂度是O(nlogn)的,这其实影响不是很大,只要出题人不毒瘤就行 。
线段树是个比较固定的序列工具,是比较常用的,可以对于序列进行一些基本操作,而且执行的比较快,但是就是代码有点长了,再考场上如果线段树不是很扎实的话,切勿尝试。
其实有一些基本操作还可以用树状数组进行处理,但是虽然树状数组代码比较短,但是呢,树状数组很多操作还是执行不了的。
分块不只是能对于序列进行操作,还可以处理纬度更高的东西,可以针对一个抽象的事情而不仅仅只有序列,再莫队优化之后就复杂度就更优秀了,分块的代码比较短,比较好理解。
一般的话,考场上碰到数据结构的题,可以先考虑树状数组树状数组,再考虑线段树,最后再考虑分块吧。线段树最常用,树状数组快代码短方便,但很多操作弄不了,分块最后再考虑吧。(这尽管跟我之前的思想有很大的不同,但是想了想还是这样比较保险,,)
代码:
#include<iostream>
#include<stdio.h>
#define LL long long
using namespace std;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int sea=1e5+7;
struct hit{int l,r;LL w,lazy;}tr[sea*4];
char s;
int n,m,x,y,xx,yy;
LL a[sea],ans,z;
void build(int l,int r,int k)
{
tr[k].l=l,tr[k].r=r;
if(l==r){tr[k].w=read();return ;}
int mid=(l+r)/2;
build(l,mid,k*2); build(mid+1,r,k*2+1);
tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
void down(int k)//下放懒标记
{
tr[k*2].lazy+=tr[k].lazy; tr[k*2+1].lazy+=tr[k].lazy;
tr[k*2].w+=tr[k].lazy*1LL*(tr[k*2].r-tr[k*2].l+1);
tr[k*2+1].w+=tr[k].lazy*1LL*(tr[k*2+1].r-tr[k*2+1].l+1);
tr[k].lazy=0;
}
void alter(int k)
{
int l=tr[k].l,r=tr[k].r;
if(l>=x&&r<=y){tr[k].w+=z*1LL*(r-l+1);tr[k].lazy+=z;return ;}
if(tr[k].lazy) down(k);
int mid=(l+r)/2;
if(x<=mid) alter(k*2); if(y>mid) alter(k*2+1);
tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
void ask(int k)
{
int l=tr[k].l,r=tr[k].r;
if(l>=xx&&r<=yy){ans+=tr[k].w;return ;}
if(tr[k].lazy) down(k);
int mid=(l+r)/2;
if(xx<=mid) ask(k*2); if(yy>mid) ask(k*2+1);
}
int main()
{
n=read(); m=read();
build(1,n,1);
for(int i=1;i<=m;i++)
{
cin>>s; ans=0;
if(s=='C') x=read(),y=read(),z=read(),alter(1);
else xx=read(),yy=read(),ask(1),printf("%lld\n",ans);
}
return 0;
}