POJ 3368 Frequent values(线段树)

来源:互联网 发布:淘宝外围会场有用吗 编辑:程序博客网 时间:2024/06/05 19:23

题意:给出一个大小为n的非降序数字序列,查询区间内出现次数最多的数字出现的次数

思路:如何建树比较难想,建树前需要一些处理

   观察一下,数字的范围为-100000-100000,给出的顺序非降序

           让每个出现过的数字对应一个区间,a[ ]记录序列,

           th[ ] 记录某个位置的数字是出现的第几个数字,cnt[ ]记录这个数字出现的次数,用cnt[ ] 建线段树记录最大值,l[ ] 记录这个数字出现的第一个位置,r[ ]记录出现的最后一个位置

           查询时将区间分为三个部分:

一、th[i] + 1 到 th[j] - 1 这几个数字的cnt最大值,查询线段树;

二、th[i] 这个数在查询区间出现的次数,r [ th[ i ] ] - i + 1

三、 th[j]这个数在查询区间出现的次数,j - l [ th[ j ] ]  + 1

#include <stdio.h>#include <string.h>#include <algorithm>#define lson l, m, rt * 2#define rson m + 1, r, rt * 2 + 1int a[100010], th[100010], cnt[100010];int l[100010], r[100010];int max[100010 * 4];void pushup(int rt){    max[rt] = max[rt * 2] > max[rt * 2 + 1] ?                max[rt * 2] : max[rt * 2 + 1];}void build(int l, int r, int rt){    if(l == r)    {        max[rt] = cnt[l];        return;    }    int m = (l + r) / 2;    build(lson); build(rson);    pushup(rt);}int query(int L, int R, int l, int r, int rt){    if(L <= l && r <= R)    {        return max[rt];    }    int m = (l + r) / 2;    int lmax = 0, rmax = 0;    if(L <= m) lmax = query(L, R, lson);    if(R > m) rmax = query(L, R, rson);    return lmax > rmax ? lmax : rmax;}int main(){    #ifdef LOCAL    freopen("data.in", "r", stdin);    #endif    int n, q;    while(scanf("%d", &n) != EOF)    {        if(n == 0) break;        scanf("%d", &q);        for(int i = 0; i < n; i++)        {            scanf("%d", &a[i]);        }        memset(th, 0, sizeof(th));        memset(cnt, 0, sizeof(cnt));        memset(l, 0, sizeof(l));        memset(r, 0, sizeof(r));        memset(max, 0, sizeof(max));        th[0] = 1; cnt[1] = 1; l[1] = 0; r[1] = 0;        int k = 1;        for(int i = 1; i < n; i++)        { //得到th[],cnt[],l[],r[]            if(a[i] == a[i - 1])            {                th[i] = k;                cnt[k]++; r[k] = i;            }            else            {                k++; th[i] = k;                cnt[k] = 1; l[k] = i; r[k] = i;            }        }        build(1, k, 1);        int x, y, ans;        while(q--)        {            scanf("%d%d", &x, &y);            x--; y--;            if(th[x] == th[y])            {                ans = y - x + 1;                //printf("1:%d %d: %d\n", x, y, ans);            }            else if(th[x] + 1 == th[y])            {                ans = (r[th[x]] - x + 1) > (y - l[th[y]] + 1) ?                        (r[th[x]] - x + 1) : (y - l[th[y]] + 1);                //printf("2:%d %d: %d\n", x, y, ans);            }            else            { //分三部分查询                ans = query(th[x] + 1, th[y] - 1, 1, k, 1);                if(r[th[x]] - x + 1 > ans) ans = r[th[x]] - x + 1;                if(y - l[th[y]] + 1 > ans) ans = y - l[th[y]] + 1;                 //printf("3:%d %d: %d\n", x, y, ans);            }            printf("%d\n", ans);        }    }    return 0;}


0 0
原创粉丝点击