题目链接
题意 :
N条线段,Q次查询。查询的是区间内线段能组成的周长最长的三角形的周长。
分析:
首先,对于三条线组成周长最长三角形的问题,我们将线段排序后从大到小依次枚举,然后判断是否能构成三角形。值得注意的是,在最坏情况下我们也只需枚举几十次。因为最坏情况是斐波那契数列,然而斐波那契数列几十个之后就在数据范围之外了。既然是区间查询K大值问题,我们考虑使用主席树。每次区间查询最多需要查询到第几十大,所以时间完全足够。
出题方题解
首先考虑区间最大的三个数能否形成三角形,如果不能,考虑区间第 二大、第三大、第四大的三个数,以此类推,直到能形成三角形。由三角 形最小的两条边大于第三边的性质可知,只需要考虑区间的前嬴嬴 大数即可 (最坏情况下区间前几大数形成了斐波那契数列) 。 时间复杂度O(nlogn∗44) 。
代码
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
const int M = MAXN * 30;
int n, q, m, tot;
int a[MAXN], t[MAXN], T[MAXN], lson[M], rson[M], c[M];
int cmp(int a, int b)
{
return a > b;
}
void init_hash()
{
for (int i = 1; i <= n; i++)
t[i] = a[i];
sort(t + 1, t + 1 + n);
m = unique(t + 1, t + 1 + n) - t - 1;
}
int build(int l, int r)
{
int root = tot++;
c[root] = 0;
if (l != r)
{
int mid = (l + r) >> 1;
lson[root] = build(l, mid);
rson[root] = build(mid + 1, r);
}
return root;
}
int hash0(int x)
{
return lower_bound(t + 1, t + 1 + m, x) - t;
}
int update(int root, int pos, int val)
{
int newroot = tot++, tmp = newroot;
c[newroot] = c[root] + val;
int l = 1, r = m;
while (l < r)
{
int mid = (l + r) >> 1;
if (pos <= mid)
{
lson[newroot] = tot++;
rson[newroot] = rson[root];
newroot = lson[newroot];
root = lson[root];
r = mid;
}
else
{
rson[newroot] = tot++;
lson[newroot] = lson[root];
newroot = rson[newroot];
root = rson[root];
l = mid + 1;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(int left_root, int right_root, int k)
{
int l = 1, r = m;
while (l < r)
{
int mid = (l + r) >> 1;
if (c[lson[left_root]] - c[lson[right_root]] >= k)
{
r = mid;
left_root = lson[left_root];
right_root = lson[right_root];
}
else
{
l = mid + 1;
k -= c[lson[left_root]] - c[lson[right_root]];
left_root = rson[left_root];
right_root = rson[right_root];
}
}
return l;
}
int pd(int a, int b, int c)
{
if (a*1ll < b*1ll + c)
return 1;
return 0;
}
int main()
{
while (scanf("%d%d", &n, &q) != EOF)
{
tot = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
init_hash();
T[n + 1] = build(1, m);
for (int i = n; i; i--)
{
int pos = hash0(a[i]);
T[i] = update(T[i + 1], pos, 1);
}
// int l,r,k;
// scanf("%d%d%d",&l,&r,&k);
// printf("%d\n",t[query(T[l],T[r+1],k)]);
while (q--)
{
int l, r, k;
scanf("%d%d", &l, &r);
int cha = r - l + 1;
if (cha > 2)
{
// printf("%d\n",t[query(T[l],T[r+1],k)]);
int a1 = t[query(T[l], T[r + 1], cha)], a2 = t[query(T[l], T[r + 1], cha - 1)], a3 = t[query(T[l], T[r + 1], cha - 2)];
int f = 0;
if (pd(a1, a2, a3))
{
printf("%lld\n", 1ll*a1 + a2 + a3);
f = 1;
}
else
{
for (int i = cha - 3; i; --i)
{
a1 = a2;
a2 = a3;
a3 = t[query(T[l], T[r + 1], i)];
if (pd(a1, a2, a3))
{
// printf("%d %d %d\n", a1, a2, a3);
printf("%lld\n", a1 + a2 + a3);
f = 1;
break;
}
}
}
if (!f)
printf("-1\n");
}
else
printf("-1\n");
}
}
return 0;
}