2016百度之星初赛Astar Round2B - 区间的价值

题意:

定义一个区间的价值为区间的最大数*最小数。现给了n(1n100000)个数,问1~n长度的最大价值分别是多少。

题解:

    用两个线段树以及快排的思想可以在O(nlog(n))的时间解决该题。

    首先用线段树找到一个区间[L,R]的最小值位置为a与最大值位置为b,[L,R]中所有包含[a,b]的区间的价值都为A[a]*A[b]。然后对[L,a-1],[a+1,R]重复这个过程。


Code:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<set>
#include<ctime>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
const int MAXN=100005;
ll MAX[MAXN<<2],MIN[MAXN<<2],A[MAXN],ANS[MAXN];
void updateMAX(int x,int l,int r,int now){
      if (l==r){
             MAX[now]=l;
             return;
      }
      int mid=(l+r)>>1;
      if (x<=mid) updateMAX(x,l,mid,now<<1);
            else  updateMAX(x,mid+1,r,(now<<1)|1);
      if (A[MAX[now<<1]]>A[MAX[now<<1|1]]) MAX[now]=MAX[now<<1];
                                     else  MAX[now]=MAX[now<<1|1];
}
void updateMIN(int x,int l,int r,int now){
      if (l==r){
             MIN[now]=l;
             return;
      }
      int mid=(l+r)>>1;
      if (x<=mid) updateMIN(x,l,mid,now<<1);
            else  updateMIN(x,mid+1,r,(now<<1)|1);
      if (A[MIN[now<<1]]<A[MIN[now<<1|1]]) MIN[now]=MIN[now<<1];
                                     else  MIN[now]=MIN[now<<1|1];
}
int queryMAX(int l,int r,int L,int R,int now)
{
      if (l>=L && r<=R) return MAX[now];
      int mid=(l+r)>>1,a=0,b=0;
      if (L<=mid) a=queryMAX(l,mid,L,R,now<<1);
      if (R>mid)  b=queryMAX(mid+1,r,L,R,now<<1|1);
      if (a==0) return b;
      if (b==0) return a;
      if (A[a]>A[b]) return a;
      return b;
}
int queryMIN(int l,int r,int L,int R,int now)
{
      if (l>=L && r<=R) return MIN[now];
      int mid=(l+r)>>1,a=0,b=0;
      if (L<=mid) a=queryMIN(l,mid,L,R,now<<1);
      if (R>mid)  b=queryMIN(mid+1,r,L,R,now<<1|1);
      if (a==0) return b;
      if (b==0) return a;
      if (A[a]<A[b]) return a;
      return b;
}
void dfs(int l,int r,int n){
      if (r<l) return;
      int a=queryMAX(1,n,l,r,1),b=queryMIN(1,n,l,r,1);
      if (a>b) swap(a,b);
      ll d=A[a]*A[b];
      for (int i=(b-a+1);i<=(r-l+1);i++)
        ANS[i]=max(ANS[i],d);
      if (A[b]>A[a]) dfs(a+1,r,n),dfs(l,a-1,n);
                else dfs(b+1,r,n),dfs(l,b-1,n);
}
int main()
{
      int n;
   //   freopen("input.txt","r",stdin);
    //  freopen("output.txt","w",stdout);
      while (~scanf("%d",&n)){
        memset(MAX,0,sizeof(MAX));
        memset(MIN,0,sizeof(MIN));
        for (int i=1;i<=n;i++){
            scanf("%I64d",&A[i]);
            updateMAX(i,1,n,1);
            updateMIN(i,1,n,1);
        }
        memset(ANS,0,sizeof(ANS));
        dfs(1,n,n);
        for (int i=1;i<=n;i++)
            printf("%I64d\n",ANS[i]);
      }
      return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值