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
#include
#include
#include
#include
#include
#include
#include
#include
#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]]=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]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;
}


你可能感兴趣的:(线段树)