POJ 2452 Sticks Problem (线段树+递归)


题意:给一个正整数序列,记为a1,a2,……an,现需找i,j,使得i<j,并且ai与aj之间的数均比ai大,均比aj小,求符合上述条件的i与j,使得j-i的最大。

分析:易知序列中的最小值比其他所有数都小,最大值比其他所有数都大,所以可以现找到最小的数与最大的数的位置,记为i,j,若i<j,则区间[i,j]内符合上述条件的最值就是j-i,然后递归求解左右区间[1,i-1],[j+1,n],若i>j,则将区间分为三段递归求解,[1,j],[j+1,i-1],[i,n]。递归边界为区间左端点>=区间右端点时返回-1。每次求区间的最大与最小值的位置可以用线段树解决。

View Code
#include <stdio.h>
#define N 50010
int n;
int a[N];
int max[4*N],min[4*N];
int MIN(int i,int j)
{
    return a[i]<a[j]?i:j;
}
int MAX(int i,int j)
{
    return a[j]>a[i]?j:i;
}
void update(int cur)
{
    int ls=cur<<1,rs=cur<<1|1;
    min[cur]=MIN(min[ls],min[rs]);
    max[cur]=MAX(max[ls],max[rs]);
}
void build(int cur,int x,int y)
{
    int mid=x+y>>1,ls=cur<<1,rs=cur<<1|1;
    if(x==y)
    {
        min[cur]=max[cur]=x;
        return;
    }
    min[cur]=n+1;
    max[cur]=0;
    build(ls,x,mid);
    build(rs,mid+1,y);
    update(cur);
}
int query_min(int cur,int x,int y,int s,int t)
{
    int mid=x+y>>1,ls=cur<<1,rs=cur<<1|1;
    if(x==s && y==t)    return min[cur];
    if(mid<s)   return query_min(rs,mid+1,y,s,t);
    if(mid+1>t) return query_min(ls,x,mid,s,t);

    int l=query_min(ls,x,mid,s,mid);
    int r=query_min(rs,mid+1,y,mid+1,t);
    return MIN(l,r);
}
int query_max(int cur,int x,int y,int s,int t)
{
    int mid=x+y>>1,ls=cur<<1,rs=cur<<1|1;
    if(x==s && y==t)    return max[cur];
    if(mid<s)   return query_max(rs,mid+1,y,s,t);
    if(mid+1>t) return query_max(ls,x,mid,s,t);

    int l=query_max(ls,x,mid,s,mid);
    int r=query_max(rs,mid+1,y,mid+1,t);
    return MAX(l,r);
}
int solve(int x,int y)
{
    if(x<1 || y>n || x>=y)    return -1;
    int id_min=query_min(1,1,n,x,y);
    int id_max=query_max(1,1,n,x,y);
    if(id_max>id_min)
    {
        int i=solve(x,id_min-1);
        int j=id_max-id_min;
        int k=solve(id_max+1,y);
        k=k>=i?k:i;
        k=k>=j?k:j;
        return k;
    }

    int i=solve(x,id_max);
    int j=solve(id_max+1,id_min-1);
    int k=solve(id_min,y);
    k=k>=i?k:i;
    k=k>=j?k:j;
    return k;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
        a[0]=-1;
        a[n+1]=100001;
        build(1,1,n);
        printf("%d\n",solve(1,n));
    }
    return 0;
}
优质内容筛选与推荐>>
1、为什么 RMAN 控制文件自动备份的名称格式没有遵循 %F 规则
2、js瀑布流
3、使用Sentinel Dashboard动态推拉数据同步到Nacos
4、VSCode sets up the remote environment
5、chrome xpath调试


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn