您的位置:首页 > 其它

线段树用法归纳

2016-04-05 23:04 330 查看
基本的创建线段树和查找一段区间内最小值与最大值。

方法一:

#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");
}


未完待续。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: