线段树

Feature


Segment tree is derived from the RMQ question, which use segment tree to speed up the updating sparse table process.

RMQ


Definition: range minimum query.

Solution: let \(d(i, j)\) to be the minimum value of \([i..i+2^{j}-1]\) \(d(i, j)= min(d(i, j-1), d(i+2^{j-1},j-1))\), let \(k\) be the max integar satisfy the constrain, \(2^k\leq R-L+1\)

Code can be devided into two parts:

void RMQ_Init(const vector<int> &A)
{
	int n= A.size();
	for (int i= 0; i< n; ++i){
		d[i][0]= A[i];
	}
	for (int j= 1; j< n; ++j){
		for (int i= 0; i+(1<<j)-1< n; ++j){
			d[i][j]= min(d[i][j-1], d[i+(1<<(j-1))][j-1]);
		}
	}
}
int RMQ(int L, int R)
{
	int k= 0;
	while ((1<<(k+1)) < R-L){
		++k;
	}
	return min(d[L][k], d[R-(1<<k)+1][k]);
}

Segment Tree 1: Point Correcting


Segment Tree 2: Interval Correction


There are two different operation determine that two kinds of interval correction.

Code 1 support these two operations:

  • \(Add(L, R, v)\), elements in interval\([L..R]\) all plus \(v\)
  • \(Query(L, R)\), calculate the sum, the max number, the min number of \([L..R]\)
/*y1, y2 are the lower bound and upper bound of the interval we do query operation, v is the number that the array is going to plus*/
void Maintain(int o, int L, int R)
{
	int lc= o*2, rc= o*2+1;
	sumv[o]= minv[o]= maxv[o]= 0;
	if (R> L){
		sumv[o]= sumv[lc]+sumv[rc];
		minv[o]= min(minv[lc], minv[rc]);
		maxv[o]= max(maxv[lc], maxv[rc]);
	}
	minv[o]+= addv[o];
	maxv[o]+= addv[o];
	sumv[o]+= addv[o]*(R-L+1);
}
void Update(int o, int L, int R)
{
	int lc= o*2, rc= o*2+1;
	if (y1<= L && y2>= R){
		addv[o]+= v;
	}
	else{
		int M= L+(R-L)/2;
		if (y1<= M){
			Update(lc, L, M);
		}
		if (y2> M){
			Update(rc, M+1, R);
		}
	}
	Maintain(o, L, R);
}
int global_min, global_max, global_sum;
void Query(int o, int L, int R, int add)
{
	if (y1<= L && y2>= R){
		global_sum+= sumv[o]+add*(R-L+1)
		global_max= max(global_max, maxv[o]+add);
		global_min= min(global_min, minv[o]+add);
	}
	else{
		int M= L+(R-L)/2;
		if (y1<= M){
			Query(o*2, L, M, add+addv[o]);
		}
		if (y2> M){
			Query(o*2+1, L, M, add+addv[o]);
		}
	}
}

Code21 support these two operations:

  • \(Set(L, R, v)\), elements in interval \([L..R]\) are set by v
  • \(Query(L, R)\), calculate the sum, the max number, the min number of \([L..R]\)
void Maintain(int o, int L, int R)
{
	int lc= o*2, rc= o*2+1;
	if (setv[o]>= 0){
		sumv[o]= setv[o]*(R-L+1);
		minv[o]= setv[o];
		maxv[o]= setv[o];
	}
	else if (R> L){
		sumv[o]= sumv[lc]+sumv[rc];
		minv[o]= min(minv[lc], minv[rc]);
		maxv[o]= max(maxv[lc], maxv[rc]);
	}
	
}
void Update(int o, int L, int R)
{
	int lc= o*2, rc= o*2+1;
	if (y1<= L && y2>= R){
		setv[o]=v;
	}
	else{
		Pushdown(o);
		int M= L+(R-L)/2;
		if (y1<= M){
			Update(lc, L, M);
		}
		else{
			Maintain(lc, L, M);
		}
		if (y2> M){
			Update(rc, M+1, R);
		}
		else{
			Maintain(rc, M+1, R);
		}
	}
	Maintain(o, L, R);
}
void Pushdown(int o)
{
	int lc= o*2, rc= o*2+1;
	if (setv[o]>= 0){
		setv[lc]= setv[rc]= setv[o];
		set[o]= -1;
	}
}
void Query(int o, int L, int R)
{
	if (setv[o]>= 0){
		global_sum+= setv[o]*(min(R, y2)-max(L, y1)+1);
		global_min= min(global_min, setv[o]);
		global_max= max(global_max, setv[o]);
	}
	else if (y1<= L && y2>= R){
		global_sum+= sumv[o];
		global_min= min(global_min, minv[o]);
		global_max= max(global_max, maxv[o]);
	}
	else{
		int M= L+(R-L)/2;
		if (y1<= M){
			Query(o*2, L, M);
		}
		if (y2> M){
			Query(o*2+1, M+1, R);
		}
	}
}

OJ Practise


POJ 1177 & HDOJ 1828


I don't know the fxxking reason why "c++ compiler" can "AC", but "g++ compiler" just fxxking show me "Runtime Error".

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

const int OUT= -1;
const int IN= 1;
const int NO= 0;
const int OL= 1;
const int INF= 0x7fffffff;
const int maxx= 20000+10;

int egl, egr;
struct Segment{
	int x;
	int yl, yh;
	int oi;
	Segment(){};
	Segment(int xx, int yyl, int yyh, int ooi) : x(xx), yl(yyl), yh(yyh), oi(ooi){}
	bool operator <(const Segment &a) const
	{
		return x< a.x || (x== a.x && oi== IN);
	}
}dt[maxx];
struct SegmentTNode{
	int l, r;
	int cov;
	int len;
	int nd;
	int lop, rop;
	SegmentTNode(){};
	SegmentTNode(int ll, int rr) : l(ll), r(rr)
	{
		cov= len= nd= lop= rop= 0;
	}
}SegTr[maxx<<2];

inline int LeftChild(int k)
{
	return k<<1;
}
inline int RightChild(int k)
{
	return ((k<<1)|1);
}
inline int Mid(int k)
{
	return (SegTr[k].l+SegTr[k].r)>>1;
}
void Build(int o, int L, int R)
{
	SegTr[o]= SegmentTNode(L, R);
	if (L== R){
		return;
	}
	int mid= Mid(o);
	Build(LeftChild(o), L, mid);
	Build(RightChild(o), mid+1, R);
}
void Maintain(int o)
{
	if (SegTr[o].cov){
		SegTr[o].len= SegTr[o].r-SegTr[o].l +1;
		SegTr[o].rop= SegTr[o].lop= SegTr[o].nd= 1;
	}
	else if (SegTr[o].l== SegTr[o].r){
		SegTr[o].lop=SegTr[o].rop= SegTr[o].nd= SegTr[o].len= 0;
	}
	else{
		int lc= LeftChild(o);
		int rc= RightChild(o);

		SegTr[o].len= SegTr[lc].len+ SegTr[rc].len;
		if (OL== SegTr[lc].rop && OL== SegTr[rc].lop){
			SegTr[o].nd= SegTr[lc].nd+ SegTr[rc].nd-1;
		}
		else{
			SegTr[o].nd= SegTr[lc].nd+ SegTr[rc].nd;
		}
		SegTr[o].rop= SegTr[rc].rop;
		SegTr[o].lop= SegTr[lc].lop;
	}
}
void Update(int o, int st)
{

	if (egl<= SegTr[o].l && SegTr[o].r<= egr){
		SegTr[o].cov+= st;
	}
	else{
		int mid= Mid(o); 
		if (egl<= mid){
			Update(LeftChild(o), st);
		}
		if (egr> mid){
			Update(RightChild(o), st);
		}
	}
	Maintain(o);
}

int main()
{
	int n, m, lb, ub, ans;
	while (EOF!= scanf("%d", &n)){
		ans= m= 0;
		lb= INF;
		ub= -INF;
		for (int xl, xr, yl, yh, i= 0; i< n; ++i){
			scanf("%d %d %d %d", &xl, &yl, &xr, &yh);
			lb= min(lb, yl);
			ub= max(ub, yh);
			dt[m++]= Segment(xl, yl, yh, IN);
			dt[m++]= Segment(xr, yl, yh, OUT);
		}

		Build(1, lb, ub-1);
		sort(dt, dt+m);

		for (int i= 0; i< m; ++i){
			int tmp= SegTr[1].len;
			if (0!= i){
				ans+= 2*(SegTr[1].nd)*(dt[i].x-dt[i-1].x);
			}
			egl= dt[i].yl;
			egr= dt[i].yh-1;
			Update(1, dt[i].oi);
			ans+= abs(SegTr[1].len-tmp);

		}
		printf("%d\n", ans);
	}

	return 0;
}
posted @ 2019-12-09 17:12  IdiotNe  阅读(70)  评论(0)    收藏  举报