通过一道例题入门线段树区间合并
例题:
输入n个 0,1数字.
操作 :
0 l r 查询[l,r]区间,输出最长连续1的长度;
1 l r x 修改[l,r]区间的值为x.
思路
区间信息问题可以用线段树,线段树的基本模板,每个节点主要维护区间最长1串,sum.len。此外,区间合并时(push_up),我们要求的两个子区间合并的最长1串,可以通过增加两个节点信息(下面还要讲一个clo),即:节点的从区间左右端点开始的1串长度, sum.llen , sum.rlen .这样在求合并时,合并区间就是max(sum[lson].len , sum[rson].len , sum[lson].rlen+sum[rson].rlen )
算法实现:我们用线段树的每个节点存储四个变量:
1.len 该区间中的最长1串.
2.llen 从左端点开始的最长1串.
3.rlen 从右端点开始的最长1串.
4.clo 标记改区间标记情况,
值为1:表示区间全为1,长度为r-l+1;
值为0: 表示区间全为0,没有1
值为-1:其他情况.
clo类似懒标记
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<stdio.h>
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int maxn=1e5+20;
int a[maxn];
struct ac{
int len,llen,rlen,clo; //len最长,llen从左开始,rlen从右开始 ,clo完全填充
}sum[maxn<<2];
struct Ans{
//记录query的返回值
int l,ll,rl;
Ans (int _l,int _ll,int _rl) :l(_l) ,ll(_ll), rl(_rl) {
}
};
int lazy[maxn<<2];
void creat(int rt,int l,int r,int v){
//更新节点
sum[rt].clo=v;
if(v)
sum[rt].len = sum[rt].llen = sum[rt].rlen=r-l+1;
else
sum