线段树和rmq

来源:互联网 发布:衢州软件开发 编辑:程序博客网 时间:2024/05/28 18:44

An easy problem A

N个数排成一列,Q个询问,每次询问一段区间内的数的极差是多少。

Input

第一行两个整数N(1≤N≤50000),Q(1≤Q≤200000)。接下来一行N个整数a1 a2 a3 ….an,(1≤ai≤1000000000)。接下来Q行,每行两个整数L,R(1≤L≤R≤N)。

Output

对于每个询问输出一行,一个整数表示区间内的极差。

Sample Input
5 33 2 7 9 101 52 33 5
Sample Output
853   

rmq算法

#include<cstdio>#include<algorithm>#include<cmath>using namespace std;const int N = 5e4 + 5;int dp[N][20][2], a[N];int power[20];int main(){    int n, q;    for (int i = 0; i < 20; i++) power[i] = 1 << i;    while (scanf("%d%d", &n, &q) != EOF) {        for (int i = 1; i <= n; i++)            scanf("%d", &a[i]);        for (int i = 1; i <= n; i++)            dp[i][0][0] = dp[i][0][1] = a[i];        for (int j = 1; (1 << j) <= n; j++)            for (int i = 1; i <= n; i++)             if(i+power[j-1]<=n){                dp[i][j][0] = max(dp[i][j - 1][0], dp[i + power[j - 1]][j - 1][0]);                dp[i][j][1] = min(dp[i][j - 1][1], dp[i + power[j - 1]][j - 1][1]);            }        for (int i = 1; i <= q; i++) {            int l, r,len;            scanf("%d%d", &l, &r);            len = (int)(log(r - l + 1) / log(2));            int maxx = max(dp[l][len][0], dp[r - power[len]+1][len][0]);//            int minn = min(dp[l][len][1], dp[r - power[len]+1][len][1]);            //printf("%d %d\n",maxx,minn);            printf("%d\n", maxx-minn);        }    }    return 0;}

查询区间的最大值时从区间两头找,效率非常高,递归也可以实现,但是效率不是很高

线段树

#include<cstdio>#include<algorithm>using namespace std;const int maxn = 5e4 + 5;struct node {    int l, r, minn, maxx;}tree[4*maxn];int n, q;void pushup(int rt){    tree[rt].maxx = max(tree[rt << 1].maxx, tree[rt << 1 | 1].maxx);    tree[rt].minn = min(tree[rt << 1].minn, tree[rt << 1 | 1].minn);}void build(int l, int r, int rt){    tree[rt].l = l, tree[rt].r = r;    if (l == r) {        scanf("%d",&tree[rt].maxx);        tree[rt].minn = tree[rt].maxx;        return;    }    int mid = r + l >> 1;    build(l, mid, rt<<1);    build(mid + 1,r, rt << 1 | 1);    pushup(rt);}int querymax(int l,int r,int rt){    if (l == tree[rt].l&&r == tree[rt].r)        return tree[rt].maxx;    int mid = tree[rt].l + tree[rt].r >> 1;    if (r <= mid) return querymax(l, r, rt << 1);    else if (l > mid) return querymax(l, r, rt << 1 | 1);    else return max(querymax(l,mid,rt<<1),querymax(mid+1,r,rt<<1|1));}int querymin(int l, int r, int rt){    if (l == tree[rt].l&&r == tree[rt].r)        return tree[rt].minn;    int mid = tree[rt].l + tree[rt].r >> 1;    if (r <= mid) return querymin(l, r, rt << 1);    else if (l > mid) return querymin(l, r, rt << 1 | 1);    else return min(querymin(l, mid, rt << 1), querymin(mid + 1, r, rt << 1 | 1));}int main(){    while (scanf("%d%d", &n, &q) != EOF) {        build(1, n, 1);        for (int i = 1; i <= q; i++) {            int a, b;            scanf("%d%d",&a,&b);            //printf("%d %d\n",querymax(a,b,1),querymin(a,b,1));            int ans = querymax(a, b, 1) - querymin(a, b, 1);            printf("%d\n",ans);        }    }    return 0;}

单独查询区间内的极值还是使用rmq快的多。但是线段树的应用更多,可以处理区间值变化的问题