ST算法 UVA11235 Frequent Values

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23846

题意:问某区间内的众数

思路:主要是练练ST算法,把左右两个不完整的区间剪去后,中间的区间用ST算法一次查询出来。区间的题应该都可以用线段树做。莫名其妙的是,在HDU上交同样的代码就WA

源码:

#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>

#include <iostream>

#include <cstdlib>

using namespace std;

#define LOCAL

int const MAXN = 100000;

int a[MAXN],dp[MAXN][20],num[MAXN],st[MAXN],en[MAXN],d[MAXN],n,m,total;

int gmax(int a,int b){return a>b?a:b;}

void init()

{

    int i,j;

    total = 0;

    for(i=0; i<n; i++){

        scanf("%d",&a[i]);

        if(i==0){

            st[total] = i;

            num[i] = total;

        }

        else if(a[i]==a[i-1]){

            num[i] = total;

        }

        else{

            en[total++] = i-1;

            st[total] = i;

            num[i] = total;

        }

    }

    en[total] = n-1;

    d[0] = 1;

    for(i=1; i<n; i++){

        if(a[i]!=a[i-1])    d[i] = 1;

        else    d[i] = d[i-1]+1;

    }

    for(i=0; i<n; i++)  dp[i][0] = d[i];

    for(j=1; (1<<(j-1))<=n; j++){

        for(i=0; (i+(1<<(j-1)))<n; i++){

            dp[i][j] = gmax(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);

        }

    }

}

int query(int a,int b)

{

    int s1 = num[a];    int s2 = num[b];

    if(s1==s2)

        return b-a+1;

    int l1 = en[s1] - a + 1;

    int l2 = b - st[s2] + 1;

//    printf("s1 = %d s2 = %d l1 = %d l2 = %d a = %d b = %d\n",s1,s2,l1,l2,a,b);

    if(s1==s2-1)

        return gmax(l1,l2);

    int l3 = 0;

    int ss = en[s1]+1;

    int ee = st[s2]-1;

    int mid = log(ee-ss+1);

    l3 = gmax(dp[ss][mid],dp[ee-(1<<mid)+1][mid]);

//    while(ss<=ee){

//        if(ss==ee){

//            l3 = gmax(l3,dp[ss][0]);

//            break;

//        }

//        int mid = log(ee-ss+1);

//        l3 = gmax(l3,dp[ss][mid]);

//        ss = ss+(1<<mid);

//    }

    l1 = gmax(l1,l2);

    return gmax(l1,l3);

}

int main()

{

    #ifdef LOCAL

        freopen("data.txt","r",stdin);

        freopen("data2.txt","w",stdout);

    #endif // LOCAL

    while(scanf("%d",&n)!=EOF && n){

        scanf("%d",&m);

        init();

        int i,j;

//        printf("left ans right\n");

//        for(i=0; i<=total; i++){

//            printf("st = %d, en = %d\n",st[i],en[i]);

//        }

//        printf("num\n");

//        for(i=0; i<n; i++)

//            printf("%d ",num[i]);

//        printf("\n");

//        for(i=0; i<n; i++){

//            for(j=0; j<20; j++)

//                printf("%d ",dp[i][j]);

//            printf("\n");

//        }

        int b,c;

        while(m--){

            scanf("%d%d",&b,&c);

            printf("%d\n",query(b-1,c-1));

        }

    }

    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值