基本的创建线段树和查找一段区间内最小值与最大值。
方法一:
#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"); }