HDU6601 主席树 三角形 Keen On Everything But Triangle

一、题意

给n个数,m个询问,每次询问,求L,R内内围成三角形的最大周长。

二、思路

我们知道,三角形三条边a,b,c应当满足a+b>c。则我们采用主席树,不断地求第1大、第二大、第K大的数判断是否满足条件即可。事实上,只要区间够大,解一定存在。三角形其本质类似斐波那契数列,所以最多约进行50项左右就可以停下来。

三、Code

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 1e5;
void work();
int tot, n, m;
int sum[maxn*40], rt[maxn*40], ls[maxn*40],
    rs[maxn*40];
int a[maxn + 10], ind[maxn + 10], len;
inline int getid(const int &val)
{
  return lower_bound(ind + 1, ind + len + 1, val) - ind;
}
int build(int l, int r)
{
  int root = ++tot;
  if (l == r) return root;
  int mid = l + r >> 1;
  ls[root] = build(l, mid);
  rs[root] = build(mid + 1, r);
  return root;
}
int update(int k, int l, int r, int root)
{
  int dir = ++tot;
  ls[dir] = ls[root], rs[dir] = rs[root], sum[dir] = sum[root] + 1;
  if (l == r) return dir;
  int mid = l + r >> 1;
  if (k <= mid)
    ls[dir] = update(k, l, mid, ls[dir]);
  else
    rs[dir] = update(k, mid + 1, r, rs[dir]);
  return dir;
}
int query(int u, int v, int l, int r, int k) 
{
  int mid = l + r >> 1,
      x = sum[ls[v]] - sum[ls[u]];
  if (l == r) return l;
  if (k <= x)  
    return query(ls[u], ls[v], l, mid, k);
  else 
    return query(rs[u], rs[v], mid + 1, r, k - x);
}
inline void init() {
  while(~scanf("%d%d", &n, &m)){
      tot=0;
      memset(sum,0,sizeof sum);
      memset(rt,0,sizeof rt);
      memset(ls,0,sizeof ls);
      memset(rs,0,sizeof rs);
      memset(ind,0,sizeof ind);
      for (register int i = 1; i <= n; ++i) scanf("%d", a + i);
      memcpy(ind, a, sizeof ind);
      sort(ind + 1, ind + n + 1);
      len = unique(ind + 1, ind + n + 1) - ind - 1;
      rt[0] = build(1, len);
      for (register int i = 1; i <= n; ++i)
        rt[i] = update(getid(a[i]), 1, len, rt[i - 1]);
        work();
    }
}
int l, r, k;
ll numm[maxn+5];
inline void work() {
  while (m--) {
    scanf("%d%d", &l, &r);
    k=r-l+1;
    if(k<=2){
        puts("-1");
    }else{
        int D=3;
        ll a=1ll*ind[query(rt[l - 1], rt[r], 1, len, k)];
        ll b=1ll*ind[query(rt[l - 1], rt[r], 1, len, k-1)];
        ll c=1ll*ind[query(rt[l - 1], rt[r], 1, len, k-2)];
    //    cout<<a<<' '<<b<<' '<<c<<endl;
//    cout<<1ll*ind[query(rt[l - 1], rt[r], 1, len, 0)]<<endl;
        ll ans=-1;
        while(D<k&&b+c<=a){
            a=b;
            b=c;
            c=1ll*ind[query(rt[l - 1], rt[r], 1, len, k-D)];
            D++;
        }
    //    cout<<a<<' '<<b<<' '<<c<<endl;
        if(b+c>a) ans=a+b+c;
        printf("%lld\n",ans);
//        printf("%d\n", ind[query(rt[l - 1], rt[r], 1, len, k)]);
    }
  }
}
int main() {
  init();
  return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值