码迷,mamicode.com
首页 > 其他好文 > 详细

区间的价值(线段树)百度之星

时间:2016-05-28 06:35:59      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:

区间的价值

Accepts: 0
Submissions: 0
Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Problem Description

我们定义“区间的价值”为一段区间的最大值*最小值。

一个区间左端点在LLL,右端点在RRR,那么该区间的长度为(R−L+1)(R-L+1)(RL+1)。

现在聪明的杰西想要知道,对于长度为kkk的区间,最大价值的区间价值是多少。

当然,由于这个问题过于简单。

我们肯定得加强一下。

我们想要知道的是,对于长度为1∼n1\sim n1n的区间,最大价值的区间价值分别是多少。

样例解释:

长度为111的最优区间为2−22-222 答案为6∗66*666

长度为222的最优区间为4−54-545 答案为4∗44*444

长度为333的最优区间为2−42-424 答案为2∗62*626

长度为444的最优区间为2−52-525 答案为2∗62*626

长度为5的最优区间为1−51-515 答案为1∗61*616

Input

多组测试数据

第一行一个数n(1≤n≤100000)n(1\leq n\leq 100000)n(1n100000)。

第二行nnn个正整数(1≤ai≤109)(1\leq a_{i}\leq 10^{9})(1a?i??10?9??),下标从111开始。

由于某种不可抗力,aia_{i}a?i??的值将会是1∼1091\sim 10^{9}110?9??内随机产生的一个数。(除了样例)

Output

输出共nnn行,第iii行表示区间长度为iii的区间中最大的区间价值。

Sample Input
5
1 6 2 4 4
Sample Output
36
16
12
12
6

题解,构造两个线段树,分别求出最大与最小的坐标。然后利用用一个类似快排的方法,每次找到最大最小后,更新所有包含该区间的区间的值,然后选择最小的下标作为分割点,继续递归划分。为什么选最小坐标呢?因为我们最后求的是最大区间价值,所以要以最小下标作为分割点(分割点之后是不会进行计算的),同时不断缩短区间,不断更新。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 100010;
int MAX[maxn<<2];
int MIN[maxn<<2];
long long ans[maxn];
long long N[maxn];
int Pos=0,n;
long long read()
{
    long long ans=0;
    char last= ,ch=getchar();
    while(ch<0 || ch>9)last=ch,ch=getchar();
    while(ch>=0 && ch<=9)ans=ans*10+ch-0,ch=getchar();
    if(last==-)ans=-ans;
    return ans;
}
void PushUP_max(int rt)
{
    if (N[MAX[rt<<1]] > N[MAX[rt<<1|1]])
        MAX[rt] = MAX[rt<<1] ;
    else
        MAX[rt] =MAX[rt<<1|1];
}
void PushUP_min(int rt)
{
    if (N[MIN[rt<<1]] < N[MIN[rt<<1|1]])
        MIN[rt] = MIN[rt<<1] ;
    else
        MIN[rt] =MIN[rt<<1|1];
}
void build_max(int l,int r,int rt)
{
    if (l == r)
    {
        MAX[rt]=++Pos;
        return ;
    }
    int m = (l + r) >> 1;
    build_max(lson);
    build_max(rson);
    PushUP_max(rt);
}
void build_min(int l,int r,int rt)
{
    if (l == r)
    {
        MIN[rt]=MAX[rt];
        return ;
    }
    int m = (l + r) >> 1;
    build_min(lson);
    build_min(rson);
    PushUP_min(rt);
}
int query_max(int L,int R,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        return MAX[rt];
    }
    int m = (l + r) >> 1;
    int ret=0;
    N[0]=0;
    if (L <= m)
    {
        int tl=query_max(L , R , lson);
        if (N[tl]>N[ret])
            ret = tl;
    }
    if (R > m)
    {
        int tr=query_max(L , R , rson);
        if (N[tr]>N[ret])ret = tr;
    }
    return ret;
}
int query_min(int L,int R,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        return MIN[rt];
    }
    int m = (l + r) >> 1;
    int ret =0;
    N[0]=999999999;
    if (L <= m)
    {
        int tl=query_min(L , R , lson);
        if (N[tl]<N[ret])
            ret = tl;
    }
    if (R > m)
    {
        int tr=query_min(L , R , rson);
        if (N[tr]<N[ret])ret = tr;
    }
    return ret;
}
void sovle(int l,int r)
{
    if (l>r) return ;
    int max_p=query_max(l , r , 1 , n , 1);
    int min_p=query_min(l , r , 1 , n , 1);
    long long num=N[max_p]*N[min_p];
    int nl,nr;
    if(max_p>min_p)
    {
        nl=min_p;
        nr=max_p;
    }
    else
    {
        nr=min_p;
        nl=max_p;
    }
    for (int i=nr-nl+1; i<=r-l+1; i++) ans[i]=max(ans[i],num);
    sovle(l,min_p-1);
    sovle(min_p+1,r);
}
int main()
{
    while(~scanf("%d",&n))
    {
        getchar();
        memset(ans,0,sizeof(ans));
        for (int i=1; i<=n; i++)
            N[i]=read();
        Pos=0;
        build_max(1 , n , 1);
        build_min(1 , n , 1);
        sovle(1,n);
        for (int i=1; i<=n; i++)
            printf("%I64d\n",ans[i]);
    }
    return 0;
}

 

区间的价值(线段树)百度之星

标签:

原文地址:http://www.cnblogs.com/scaugsh/p/5536681.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!