线段树用法归纳

基本的创建线段树和查找一段区间内最小值与最大值。

方法一:

#include<iostream>
#include<cstring>
#include<stdio.h>

using namespace std;
struct sto
{
    int maxx,minn;
};
int A[1000300];
sto M[8000300];
//构建线段树,目的:得到M数组.
void build(int node, int b, int e)
{
	if (b == e)
	{
	    M[node].maxx = b; //只有一个元素,只有一个下标
	    M[node].minn=b;
	}
	else
	{
		build(2 * node, b, (b + e) / 2);
		build(2 * node + 1, (b + e) / 2 + 1, e);

		if (A[M[2 * node].minn] <= A[M[2 * node + 1].minn])
		{
		    M[node].minn = M[2 * node].minn;
		    M[node].maxx=M[2*node+1].maxx;
		}
		else
		{
		    M[node].minn = M[2 * node + 1].minn;
		    M[node].maxx=M[2*node].maxx;
		}
	}
}

//找出区间 [i, j] 上的最小值的索引
int query(int node, int b, int e, int i, int j)
{
	int p1, p2;

	//查询区间和要求的区间没有交集
	if (i > e || j < b)
		return -1;
	if (b >= i && e <= j)
		return M[node].minn;
	p1 = query(2 * node, b, (b + e) / 2, i, j);
	p2 = query(2 * node + 1, (b + e) / 2 + 1, e, i, j);

	//return the position where the overall
	//minimum is
	if (p1 == -1)
		return p2;
	if (p2 == -1)
		return p1;
	if (A[p1] <= A[p2])
		return  p1;
	return  p2;
}
int query2(int p,int b,int e,int l,int r)
{
    if(b>r||e<l)
        return -1;
    if(l<=b&&r>=e)
        return M[p].maxx;
    int q1=query2(p<<1,b,(b+e)/2,l,r);
    int p1=query2(p<<1|1,(b+e)/2+1,e,l,r);
    if(p1==-1)
        return q1;
    if(q1==-1)
        return p1;
    if(A[p1]<A[q1])
        return q1;
    return p1;
}
int main()
{
	//下标1起才有意义,否则不是二叉树,保存下标编号节点对应区间最小值的下标.
	memset(M, -1, sizeof(M));
	int n, k;
	scanf("%d%d",&n,&k);
	for (int i = 0; i < n; ++i)
		scanf("%d", &A[i]);
	build(1, 0, n - 1);
	for (int i = 0; i + k-1 < n;++i)
	printf("%d%c", A[query(1,0,n - 1, i, i+k-1)],(i+k-1!=n-1)?' ':'\n');
    for (int i = 0; i + k-1 < n;++i)
	printf("%d%c", A[query2(1,0,n - 1, i, i+k-1)],(i+k-1!=n-1)?' ':'\n');
	return 0;
}

方法二:

#include<iostream>
#include<stdio.h>

using namespace std;

struct tree
{
	int left;
	int right;
	int maxx;
	int minn;
};
tree tr[4000300];
int max(int a, int b)
{
	return a < b ? b : a;
}
int min(int a, int b)
{
	return a < b ? a : b;
}
void build(int l, int r, int rt)
{
	tr[rt].left = l;
	tr[rt].right = r;
	if (l == r)
	{
		scanf("%d", &tr[rt].maxx);<span style="white-space:pre">	</span>//这里尤其需要注意,是输入rt位置的值,而不是l位置的值。
		tr[rt].minn = tr[rt].maxx;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
	tr[rt].maxx = max(tr[rt << 1].maxx, tr[rt << 1 | 1].maxx);
	tr[rt].minn = min(tr[rt << 1].minn, tr[rt << 1 | 1].minn);
}
int resmax = -99999999, resmin = 99999999;
void quemax(int l, int r, int rt)
{
	if (tr[rt].left >= l&&tr[rt].right <= r)
	{
		if (resmax<tr[rt].maxx)
			resmax= tr[rt].maxx;
		return;
	}
	int mid = (tr[rt].left + tr[rt].right) >> 1;
	if (mid >= r)
		quemax(l, r, rt << 1);
	else
		if (mid + 1 <= l)
			quemax(l, r, rt << 1 | 1);
		else
		{
			quemax(l, mid, rt << 1);
			quemax(mid + 1, r, rt << 1 | 1);
		}
}
void quemin(int l, int r, int rt)
{
	if (tr[rt].left >= l&&tr[rt].right <= r)
	{
		if (resmin > tr[rt].minn)
		  resmin=tr[rt].minn ;
		return;
	}
	int mid = (tr[rt].left + tr[rt].right) >> 1;
	if (mid >= r)
		quemin(l, r, rt << 1);
	else
		if (mid + 1 <= l)
			quemin(l, r, rt << 1 | 1);
		else
		{
			quemin(l, mid, rt << 1);
			quemin(mid + 1, r, rt << 1 | 1);
		}
}
int main()
{
	//freopen("input.txt", "r", stdin);
	int n, k;
	scanf("%d%d", &n, &k);
	build(1, n, 1);
	for (int i = 1; i + k <= n + 1; i++)
	{
		resmin = 99999999;
		quemin(i, i + k - 1, 1);
		printf("%d%c", resmin, (i + k == n + 1 ) ? '\n' : ' ');
	}
	for (int i = 1; i + k <= n + 1; i++)
	{
		resmax = -99999999;
		quemax(i, i + k - 1, 1);
		printf("%d%c", resmax, (i + k == n + 1 ) ? '\n' : ' ');
	}

	//system("pause");
}


未完待续。。。


你可能感兴趣的:(C++,算法,线段树,ACM)