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

区间的价值

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)(R−L+1)。

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

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

我们肯定得加强一下。

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

样例解释:

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

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

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

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

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

Input

多组测试数据

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

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

由于某种不可抗力,aia_{i}a?i??的值将会是1∼1091\sim 10^{9}1∼10?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;
}
时间: 2024-10-12 12:54:12

区间的价值(线段树)百度之星的相关文章

字典树-百度之星-Xor Sum

Xor Sum Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大.Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助.你能证明人类的智慧么? Input 输入包含若干组测试数

FOJ 2171 防守阵地 II 区间求和区间查询 线段树

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2171 题意: 给定n长序列,常数m,q个询问 对于每个询问x 1.求[x, x+m-1] 区间和 2.[x,x+m-1]区间的所有元素-1 线段树裸题,不知为何全用longlong会re,只能改成部分longlong #include<stdio.h> #include<string.h> #define ll long long #define LL int #define L(x) (x*

HDU 5700——区间交——————【线段树+枚举】

区间交 Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 567    Accepted Submission(s): 279 Problem Description 小A有一个含有n个非负整数的数列与m个区间.每个区间可以表示为li,ri. 它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大. 例如样例中,选择[2,5]

【BZOJ4653】[Noi2016]区间 双指针法+线段树

[BZOJ4653][Noi2016]区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度.区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值. 求所有合法方案中最小

线段树———区间最大数(线段树入门)

线段树初级(区间最大数) 其实就是对树进行二分查找      (当然需要结合递归) 思路: 要从区间中找到最大数,当然可以暴力求解,但你不怕超时吗??? so      让我们来学习线段树吧!!!!!!!!!!!!!!! 在c++里下面这个代码是极快的(哇咔咔!!!) 题目描述 给出一列数共N个,将其从1到N编号,进行M次查询[X, Y](X<=Y),给出第X个数到第Y个数间最大的数. 输入 一组测试数据,第一行输入N,M(1<=N, M<=10^5),第二行N个数:之后M行,每行分别为

线段树之区间最大数(线段树入门)

线段树初级(区间最大数) 其实就是对树进行二分查找      (当然需要结合递归) 思路: 要从区间中找到最大数,当然可以暴力求解,但你不怕超时吗??? so      让我们来学习线段树吧!!!!!!!!!!!!!!! #include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 100010 struct N {     int l, r, max

【BZOJ3878】【Ahoi2014】奇怪的计算器 维护区间性质。线段树

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44037685"); } 题解: 先排序然后插入线段树 用线段树每次对全区间进行操作. 然后维护哪些段区间溢出了,对这段区间进行赋值. 溢出处理: 一个区间的左端点大于最大值,或者右端点小于最小值 那么这个区间就该被覆盖. 覆盖,加特

Benelux Algorithm Programming Contest 2014 Final ACM-ICPC Asia Training League 暑假第一阶段第二场 E. Excellent Engineers-单点更新、区间最值-线段树 G. Growling Gears I. Interesting Integers-类似斐波那契数列-递推思维题

先写这几道题,比赛的时候有事就只签了个到. E. Excellent Engineers 传送门: 这个题的意思就是如果一个人的r1,r2,r3中的某一个比已存在的人中的小,就把这个人添加到名单中. 因为是3个变量,所以按其中一个变量进行sort排序,然后,剩下的两个变量,一个当位置pos,一个当值val,通过线段树的单点更新和区间最值操作,就可以把名单确定. 代码: 1 //E-线段树 2 #include<iostream> 3 #include<cstdio> 4 #incl

HDU 3308 LCIS (经典区间合并)【线段树】

<题目链接> 题目大意: 给你一段序列,对其进行两种操作,一是修改某个序号的点的值:二是查询某个区间的LCIS(最长上升子序列). 解题分析: 线段树区间合并的典型例题,用求某个区间的LCIS时,需要比较三个值,一是左区间的LCIS,二是右区间的LCIS,三是左右子区间合并的LCIS.最重要的是第三点如何实现,实现第三点需要维护一个最长后缀上升子序列和最长前缀上升子序列. #include <cstdio> #include <cstring> #include <

HDU 1540 Tunnel Warfare(区间合并)【线段树】

<题目链接> 题目大意: 题意:一个长度为n的线段,下面m个操作 D x 表示将单元x毁掉 R  表示修复最后毁坏的那个单元 Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0. 解题分析: 用线段树求指定点所在的最长连续区间,属于线段树区间合并类型的题,线段树的每个节点需要维护三个值,分别是对应区间的最长连续区间长度,对应区间最长连续区间前缀,对应区间最长连续后缀,然后就是在每次update之后都维护一下这三个值就行.并且注意一下query 时的操作. 1 #i