1. 程式人生 > >2016百度之星初賽Astar Round2B

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;
}