线段树

1、中心思想

二分, 每查找一个区间或者修改一个区间的时候,一层一层往下二分,找到

区间的左端点和右端点是否是在应该修改的区间内,而后进行修改操做...

2、基本操做

一、建树

首先你要弄明白这棵线段树是干什么的,即这棵线段树的节点要存储哪些信息

若是你不知道线段树里要存储哪些信息,回答如下三个问题:

①对于要求的输出,须要维护哪些信息(线段树节点里要存什么)?
②这些信息是否能够直接获得?
③若是不能,须要维护哪些信息来间接得到?node

而后咱们要作的事情就是:

两件事:由上而下干什么? 由下而上干什么?
由上而下的过程——初始化
由下而上的过程——合并区间信息
从上往下跑一圈又必需要倒回去的算法——递归。ios

那么就是递归实现的喽。git

要开四倍空间

来自沙雕网友的解答:

理论上是2n-1的空间,可是你递归创建的时候当前节点为r
,那么左右孩子分别是2r,2r+1,此时编译器并不知道递归已结束,
由于你的结束条件是在递归以前的,因此编译器会认为下标访问出错,也就是空间开小了,
应该再开大2倍。有时候可能你发现开2,3倍的空间也能够AC,那只是由于测试数据并无那么大。算法

主要的思路就是递归加二分
看看代码吧(~~怀念那学长看着我打代码,强行改我码风的日子)测试

void build(ll l,ll r,ll rt) {
	t[rt].len = r - l + 1;
	if(l == r) {
		t[rt].sum = read();
		return;
	}
	ll m = (l + r) >> 1;
	build(l, m, lson);
	build(m + 1, r ,rson);
	pushup(rt);
}

单点查询

知道二分与递归以后,单点查询那不就成了一个,二分求解的过程了嘛ui

void ask(int k)
{
    if(tree[k].l==tree[k].r) //当前结点的左右端点相等,那么说明是叶子节点,是最终答案 
    {
        ans=tree[k].w;
        return ;
    }
    int m=(tree[k].l+tree[k].r)/2; // 二分查找
    if(x<=m) ask(k*2);
    else ask(k*2+1);
}

单点修改

与单点查询没有什么区别,就是加了修改操做
还有一个回溯的过程this

void add(int k)
{
    if(tree[k].l==tree[k].r)//找到目标位置 
    {
        tree[k].w+=y;
        return;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(x<=m) add(k*2);
    else add(k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//全部包含结点k的结点状态更新 
}

懒标记

由于线段树的时候,有一些节点虽然咱们下放了值了,也加上了,可是咱们并无用到这个地方
那么咱们能够如今查询到的地方打上一个lazy标记(称为懒标记),而后每次查到这里的时候
就将当前的区间维护的值,与lazy标记处理一下就行了,这样咱们就没有必要再向下跑到叶子节点
而后在合并区间信息了,很麻烦,也很慢...spa

区间修改

当他区间修改的时候,无非就是三种状况code

一、当你查到的区间与须要修改的区间这样时

like this
blog

由于中心思想是二分,那么咱们能够求出当前查到的区间的mid而后与

须要修改的区间的l和r进行比较,而后继续递归。

二、当你须要修改的区间在你当前查询的区间中时

like this

按照上边的思路,咱们要取查询到的区间的两边段点,而后按照mid的状况更新

三、当你查询到的区间彻底在须要修改的区间内时

like this

由于彻底在区间内了,因此直接修改就行了

看一下代码吧

void updata(ll L,ll R,ll c,ll l,ll r,ll rt){
	if(L <= l && r <= R){
		t[rt].sum += t[rt].len * c;
		t[rt].lazy += c;
		return ;
	}
	pushdown(rt);
	ll m = (l + r) >> 1;
	if(L <= m) updata(L,R,c,l,m,lson);
	if(R > m) updata(L,R,c,m + 1,r,rson);
	pushup(rt);
}

四、区间查询

和上边的差很少,状况也是上边的三种状况,而后这样咱们能够去一个ans而后累加就好了

ll query(ll L,ll R,ll l,ll r,ll rt){
	if(L <= l && r <= R) return t[rt].sum;
	pushdown(rt);
	ll m = (l + r) >> 1,ans=0;
	if(L <= m) ans+=query(L, R, l, m, lson);
	if(R > m) ans+=query(L, R, m + 1, r, rson);
	return ans;
}

最后合并总的代码(由于单点查询与单点修改能够仿照区间查询与区间修改上来我就不放了)

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<string>
#define ll long long
#define N 1000010
#define lson rt << 1
#define rson rt << 1 | 1

using namespace std;
ll n,m,rt;
struct node {
	ll sum,lazy,len;
} t[N << 2 | 1];
ll read() {
	ll s=0,f=0;
	char ch=getchar();
	while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
	while(isdigit(ch)) s=s*10+(ch^48),ch=getchar();
	return f?-s:s;
}
void build(ll l,ll r,ll rt);
void pushup(ll rt);
void pushdown(ll rt);
void updata(ll L,ll R,ll c,ll l,ll r,ll rt);
ll query(ll L,ll R,ll l,ll r,ll rt);

int main() {
	n = read(), m = read();
	build(1,n,1);
	for(ll i = 1, opt, l, r, k; i <= m; i++){
		opt = read(),l = read(),r = read();
		if(opt == 1){k = read();updata(l,r,k,1,n,1);}
		else printf("%lld\n",query(l,r,1,n,1));
	}
	return 0;
}

void build(ll l,ll r,ll rt) {
	t[rt].len = r - l + 1;
	if(l == r) {
		t[rt].sum = read();
		return;
	}
	ll m = (l + r) >> 1;
	build(l, m, lson);
	build(m + 1, r ,rson);
	pushup(rt);
}

void pushup(ll rt) {
	t[rt].sum = t[lson].sum + t[rson].sum;
}

void pushdown(ll rt) {
	if(t[rt].lazy) {
		t[lson].lazy += t[rt].lazy;
		t[rson].lazy += t[rt].lazy;
		t[lson].sum += t[lson].len * t[rt].lazy;
		t[rson].sum += t[rson].len * t[rt].lazy;
		t[rt].lazy = 0;
	}
}

void updata(ll L,ll R,ll c,ll l,ll r,ll rt){
	if(L <= l && r <= R){
		t[rt].sum += t[rt].len * c;
		t[rt].lazy += c;
		return ;
	}
	pushdown(rt);
	ll m = (l + r) >> 1;
	if(L <= m) updata(L,R,c,l,m,lson);
	if(R > m) updata(L,R,c,m + 1,r,rson);
	pushup(rt);
}

ll query(ll L,ll R,ll l,ll r,ll rt){
	if(L <= l && r <= R) return t[rt].sum;
	pushdown(rt);
	ll m = (l + r) >> 1,ans=0;
	if(L <= m) ans+=query(L, R, l, m, lson);
	if(R > m) ans+=query(L, R, m + 1, r, rson);
	return ans;
}
相关文章
相关标签/搜索