UVa 11235 Frequent Values

训练指南 P198 例题

在一个非降序数组中寻找区间内出现次数最多的值的出现次数。

用线段树和RMQ都能AC。

RMQ解法

#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 0x7fffffff
using namespace std;
int n;
int a[120000];
int nb[120000],b[120000],bv[120000],l[120000],r[120000],ll[120000],rr[120000];
int d[120000][50];
bool initRMQ()
{
    int i,j;
    for (i=1; i<=n; i++)
    {
        d[i][0]=b[i];
    }
    for (j=1; (1<<j)<=n; j++)
    {
        for (i=1; i+j-1<=n; i++)
        {
            d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
        }
    }
    return true;
}
int queryRMQ(int l,int r)
{
    if (r < l)
        return 0;
    int i;
    i=0;
    while ((1<<(i+1)) <= r-l+1)
        i++;
    return max(d[l][i],d[r-(1<<i)+1][i]);
}
int maxx(int a,int b,int c)
{
    return max(max(a,b),c);
}
int main()
{
    int m,q,i,j,t1,t2;
    while (true)
    {
        scanf("%d",&m);
        if (m == 0)
            break;
        scanf("%d",&q);
        n=0;
        bv[n]=INF;
        for (i=1; i<=m; i++)
        {
            scanf("%d",a+i);
            if (bv[n] != a[i])
            {
                r[n]=i-1;
                n++;
                nb[i]=n;
                l[n]=i;
                b[n]=1;
                bv[n]=a[i];
            }
            else
            {
                nb[i]=n;
                b[n]++;
            }
        }
        r[n]=i-1;
        j=0;
        for (i=1; i<=m; i++)
        {
            if (bv[j] != a[i])
                j++;
            ll[i]=l[j];
            rr[i]=r[j];
        }
        initRMQ();
      /*  for (i=1; i<=n; i++)
            printf("%d ",b[i]);
        printf("\n");
        for (i=1; i<=n; i++)
            printf("%d ",bv[i]);
        printf("\n");
        for (i=1; i<=n; i++)
            printf("%d ",l[i]);
        printf("\n");
        for (i=1; i<=n; i++)
            printf("%d ",r[i]);
        printf("\n");
        for (i=1; i<=m; i++)
            printf("%d ",ll[i]);
        printf("\n");
        for (i=1; i<=m; i++)
            printf("%d ",rr[i]);
        printf("\n");
        for (i=1; i<=m; i++)
            printf("%d ",nb[i]);
        printf("\n");*/
        while (q--)
        {
            scanf("%d%d",&t1,&t2);
            if (ll[t1] == ll[t2])
            {
                //printf("1->");
                printf("%d\n",t2-t1+1);
            }
            else
            {
              //  printf("2->");
                printf("%d\n",maxx(rr[t1]-t1+1,t2-ll[t2]+1,queryRMQ(nb[rr[t1]+1],nb[ll[t2]-1])));
              //  printf("%d %d %d %d %d\n",rr[t1]-t1+1,t2-ll[t2]+1,queryRMQ(nb[rr[t1]+1],nb[ll[t2]-1]),nb[rr[t1]+1],nb[ll[t2]-1]);
            }
        }
    }
}
线段树解法

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct T
{
    int l;
    int r;
    int mid;
    int flag;
    int v;
    int lv,rv;
    int lc,rc;
};
T tree[1000000];
int cnt[1000000];
int a[1000000];
int n,q;
int min(int a,int b)
{
    return a>b?b:a;
}
int max(int a,int b)
{
    return a>b?a:b;
}
void buildTree(int l,int r,int c)
{
    int t,i;
    tree[c].l=l;
    tree[c].r=r;
    tree[c].mid=(l+r)>>1;
    if (l == r)
    {
        tree[c].v=1;
        tree[c].lv=1;
        tree[c].rv=1;
        tree[c].lc=a[l];
        tree[c].rc=a[l];
        return ;
    }
    buildTree(l,tree[c].mid,c<<1);
    buildTree(tree[c].mid+1,r,c<<1|1);
    tree[c].lv=tree[c<<1].lv;
    tree[c].lc=tree[c<<1].lc;
    tree[c].rv=tree[c<<1|1].rv;
    tree[c].rc=tree[c<<1|1].rc;
    tree[c].v=max(tree[c<<1].v,tree[c<<1|1].v);
    if (tree[c<<1].rc == tree[c<<1|1].lc)
    {
        tree[c].v=max(tree[c].v,tree[c<<1].rv+tree[c<<1|1].lv);
        if (tree[c<<1].lc == tree[c<<1].rc)
        {
            tree[c].lv=tree[c<<1].lv+tree[c<<1|1].lv;
            tree[c].v=max(tree[c].v,tree[c].lv);
        }
        if (tree[c<<1|1].lc == tree[c<<1|1].rc)
        {
            tree[c].rv=tree[c<<1].rv+tree[c<<1|1].rv;
            tree[c].v=max(tree[c].v,tree[c].rv);
        }
    }
}
int query(int l,int r,int c)
{
    int t1,t2;
    if (tree[c].l == l && tree[c].r == r)
    {
        return tree[c].v;
    }
    if (l > tree[c].mid)
        return query(l,r,c<<1|1);
    else if (r <= tree[c].mid)
        return query(l,r,c<<1);
    else
    {
        t1=query(l,tree[c].mid,c<<1);
        t2=query(tree[c].mid+1,r,c<<1|1);
        if (tree[c<<1].rc != tree[c<<1|1].lc)
        {
            return t1>t2?t1:t2;
        }
        else
        {
            t1=t1>t2?t1:t2;
            t2=min(tree[c<<1].rv,tree[c].mid-l+1)+min(tree[c<<1|1].lv,r-tree[c].mid);
            return t1>t2?t1:t2;
        }
    }
}
int main()
{
    int i,t1,t2;
    while (1)
    {
        scanf("%d",&n);
        if (n == 0)
            break;
        scanf("%d",&q);
        for (i=1; i<=n; i++)
        {
            scanf("%d",a+i);
        }
        buildTree(1,n,1);
        while (q--)
        {
            scanf("%d%d",&t1,&t2);
            printf("%d\n",query(t1,t2,1));
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值