Hdu5696 区间的价值(花式水)

题目链接

又花式水过了一题,正解不知道是啥,可能很高端的样子。

题意

N 个数,某个子区间的价值为这个区间内最大值*最小值。
求长度为1的所有子区间中价值最大的那个是多少
求长度为2的所有了区间中价值最大的那个是多少

求长度为N的所有了区间中价值最大的那个是多少

思路

pre: maxRange[i]表示区间长度为i的所有区间中价值最大那个值。

把数从大到小排个序,准备一个空序列,然后依次加入序列中,那么对于当前加入的数x,已经出现的数一定大于等于x,假设位置为p,算出向左至pl,向右至pr,这个区间 [pl,pr] 是已经加入了的,也就是说这些数都>=x,所以这个区间的价值为 val=xmax(Apl...Apr) 。这个区间长度为 len=prpl+1 ,更新 maxRangelen=max(maxRangelen,val) .

最后输出答案 anweri=max(maxRangei...n) .这里为什么成立呢,因为当我们加入一个数算出区间长度为k,价值为v,那么这个区间的子区间(长度小于k)的价值一定大于等于v…

所以我们用个线段树啥的,查询一下区间最大值就可以了,计算两边位置 pl pr ,可以用dp来写,我用了两个并查集来更新每个位置的 pl pr

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define DEFMID  int mid = l + r >> 1
#define L_SON    (v << 1)
#define R_SON    (v << 1 | 1)
#define L_RANGE  l, mid
#define R_RANGE  mid + 1, r

typedef long long LLONG;
typedef unsigned long long ULLONG;
typedef std::pair<int, int> PII;
typedef std::vector<int> VI;
#define debug(x) std::cout << #x << " = " << x << std::endl;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;

int A[N];
int C[N];   //是否已经加入
PII stA[N]; //用于排序用

int maxTree[N << 2];
LLONG maxRange[N];
LLONG answer[N];

inline void pushUp(int v) {
  maxTree[v] = std::max(maxTree[L_SON] , maxTree[R_SON]);
}

inline void build(int l, int r, int v) {
  if (l >= r) {
    maxTree[v] = A[l];
    return;
  }
  DEFMID;
  build(L_RANGE, L_SON);
  build(R_RANGE, R_SON);
  pushUp(v);
}

inline int query(int l, int r, int x, int y, int v) {
  if (l >= x && r <= y) {
    return maxTree[v];
  }
  DEFMID;
  int rlt =  0;
  if (mid >= x) rlt = query(L_RANGE, x, y, L_SON);
  if (mid < y) rlt = std::max(rlt, query(R_RANGE, x, y, R_SON));
  return rlt;
}

int rootLeft[N];    //向左pl
int rootRight[N];   //向右pr

inline int findSet(int root[], int x) {
  return root[x] = root[x] == x ? x : findSet(root, root[x]);
}

inline void unionSetLeft(int u) {
  if (~C[u + 1]) {
    int v = findSet(rootRight, u + 1);
    rootRight[u] = v;
  }
  if (~C[u - 1]) {
    int v = findSet(rootLeft, u - 1);
    rootLeft[u] = v;
  }

  if (~C[u + 1]) {
    int v = findSet(rootLeft, u);
    rootLeft[u + 1] = v;
  }
  if (~C[u - 1]) {
    int v = findSet(rootRight, u);
    rootRight[u - 1] = v;
  }
}

int main() {
  int n, m;
  for (; ~scanf("%d", &n);) {
    for (int i = 0; i <= n + 1; ++i) {
      rootLeft[i] = i;
      rootRight[i] = i;
      C[i] = -1;
      maxRange[i] = -1;
    }
    for (int i = 1; i <= n; ++i) {
      scanf("%d", A + i);
      stA[i] = std::make_pair(A[i], i);
    }
    std::sort(stA + 1, stA + n + 1);
    build(1, n, 1);
    for (int i = n; i > 0; --i) {
      unionSetLeft(stA[i].second);
      int left = findSet(rootLeft, stA[i].second);
      int rit = findSet(rootRight, stA[i].second);
      int tmpMax = query(1, n, left, rit, 1);
      maxRange[rit - left + 1] = std::max(1LL * tmpMax * stA[i].first, maxRange[rit - left + 1]);
      C[stA[i].second] = 1;
    }
    int cur = n;
    for (int i = n; i > 0; --i) {
      if (maxRange[i] > maxRange[cur]) cur = i;
      answer[i] = maxRange[cur];
    }
    for (int i = 1; i <= n; ++i) {
      printf("%I64d\n", answer[i]);
    }
  }
  return 0;
}

/*
1 6 4 4 2 4 4

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值