线段树模板题 contest 线段树 T5

Description

给定一个长为n的序列,接下来m次操作,每次操作会对序列某段区间内所有数加上一个值,或是询问一段区间的和。


Input

第一行,n和m,代表序列长度为n,并有m个操作第二行有n个数字,表示序列中的每个元素接下来m行,每行形如Q a b 代表查询[a,b]的区间和,或C a b c 代表对[a,b]中的所有数都增加c


Output

每行输出对应每一个查询的结果


Hint

n,m <=10^5。


Solution

对于这道题我想说我查错十几分钟最后还是死在了long long格式化输入输出要用lld上面。。。(充分证明我有多么傻逼)


呃感觉线段树就很像树状数组和静态RMQ结合起来了(???)然后其实感觉理解起来挺简单的就是建一颗树,二分地来存区间,然后访问的时候只需要去看区间的边界就可以了,因为他是二分的所以肯定是能找到要查询的区间的。然后单点修改也很简单就不说了区间修改的话其实就是用一个tag记录整个区间需要加的值,然后只需要依次传递,不需要每次区间修改都要把这个区间的结点的所有儿子都修改了,用tag标记然后等到要查询的时候再修改就可以了。


注意事项:

1.首先long long是必要的,然后long long要用lld啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊。。。。。
2.然后就是如果是区间和的区间修改的话就要乘(r-l+1),X_Download的过程里面也需要乘(mid-l+1)和(r-mid)。
3.我是傻逼,没了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define maxn 200005
#define mid ((l+r)>>1)
#define int long long
using namespace std;
int leftt[maxn],rightt[maxn],TOL_seg[maxn],aa[maxn],lazytag[maxn];
int root,newp,n,m,a,b,c;
char s[maxn];
void X_Upload(int now){
	TOL_seg[now]=TOL_seg[leftt[now]]+TOL_seg[rightt[now]];
}
void X_Build(int &now,int l,int r){
	now=++newp;
	if(l==r){
		TOL_seg[now]=aa[l];
		return;
	}
	X_Build(leftt[now],l,mid);
	X_Build(rightt[now],mid+1,r);
	X_Upload(now);
}
void X_Download(int now,int l,int r){
	if(lazytag[now]==0)return;
	TOL_seg[leftt[now]]+=lazytag[now]*(mid-l+1);
	TOL_seg[rightt[now]]+=lazytag[now]*(r-mid);
	lazytag[leftt[now]]+=lazytag[now];
	lazytag[rightt[now]]+=lazytag[now];
	lazytag[now]=0;
}
void X_Update(int now,int l,int r,int x,int y,int dx){
	if(x>r||y<l)return;
	if(x<=l&&y>=r){
		TOL_seg[now]+=dx*(r-l+1);
		lazytag[now]+=dx;
		return;
	}
	X_Download(now,l,r);
	if(y<=mid){
		X_Update(leftt[now],l,mid,x,y,dx);
	}
	else{
		if(x>mid){
		    X_Update(rightt[now],mid+1,r,x,y,dx);
		}
		else{
			X_Update(leftt[now],l,mid,x,y,dx);
			X_Update(rightt[now],mid+1,r,x,y,dx);
		}
	}
	X_Upload(now);
}
int X_Search(int now,int l,int r,int x,int y){
	if(x>r||y<l)return 0;
	if(x<=l&&y>=r){
		return TOL_seg[now];
	}
	X_Download(now,l,r);
	return X_Search(leftt[now],l,mid,x,y)+X_Search(rightt[now],mid+1,r,x,y);
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld",&aa[i]);
	}
	X_Build(root,1,n);
	for(int i=1;i<=m;i++){
		scanf("%s",&s[i]);
		if(s[i]=='Q'){
			scanf("%lld%lld",&a,&b);
			printf("%lld\n",X_Search(root,1,n,a,b));
		}
		if(s[i]=='C'){
			scanf("%lld%lld%lld",&a,&b,&c);
			X_Update(root,1,n,a,b,c);
		}
	}
	return 0;
}
posted @ 2018-11-30 16:54  虚拟北方virtual_north。  阅读(131)  评论(0编辑  收藏  举报