题目链接:点击查看
题目大意:给出一个长度为 n 的数列 a ,再给出 q 次询问,每次询问给出一个区间 [ l , r ] ,要求从区间内选出三个数,使得构成的三角形周长最大,如果无解输出 - 1
题目分析:如果将区间 [ l , r ] 内的数列排个序的话,肯定从大到小找连续相邻的三个数是最优的,这样一来,我们必须找到相邻的 x , y , k,满足 a[ x ] + a[ y ] > a[ k ] ,那么我们反过来想,如果不满足条件的话,即恰好有 a[ x ] + a[ y ] = a[ k ] ,这不就是斐波那契数列了,因为 1e9 以内只有 44 项斐波那契数列,所以对于每次查询,我们直接暴力找到区间 [ l , r ] 内前 50 大的数,然后贪心寻找答案即可,找到区间第 k 大的操作可以交给主席树来实现
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
int a[N];
/*主席树*/
struct Node
{
int l,r,sum;
}tree[N*40];
int root[N],cnt;
void change(int pos,int &k,int l,int r)
{
tree[cnt++]=tree[k];
k=cnt-1;
tree[k].sum++;
if(l==r)
return;
int mid=l+r>>1;
if(pos<=mid)
change(pos,tree[k].l,l,mid);
else
change(pos,tree[k].r,mid+1,r);
}
int query(int i,int j,int l,int r,int k)//左根,右根,当前区间,第k大
{
if(l==r)
return l;
int d=tree[tree[j].r].sum-tree[tree[i].r].sum;
int mid=l+r>>1;
if(k<=d)
return query(tree[i].r,tree[j].r,mid+1,r,k);
else
return query(tree[i].l,tree[j].l,l,mid,k-d);
}
/*主席树*/
/*离散化*/
vector<int>node;
void discreate()
{
sort(node.begin(),node.end());
node.erase(unique(node.begin(),node.end()),node.end());
}
int get_id(int x)
{
return lower_bound(node.begin(),node.end(),x)-node.begin()+1;
}
/*离散化*/
void init()
{
node.clear();
root[0]=0;
tree[0].l=tree[0].r=tree[0].sum=0;
cnt=1;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
node.push_back(a[i]);
}
discreate();
for(int i=1;i<=n;i++)
{
root[i]=root[i-1];
change(get_id(a[i]),root[i],1,n);
}
while(m--)
{
vector<LL>num;
int l,r,len;
LL ans=-1;
scanf("%d%d",&l,&r);
len=r-l+1;
for(int i=1;i<=min(len,50);i++)
num.push_back(node[query(root[l-1],root[r],1,n,i)-1]);
for(int i=0;i+2<num.size();i++)
if(num[i+1]+num[i+2]>num[i])
{
ans=num[i]+num[i+1]+num[i+2];
break;
}
printf("%lld\n",ans);
}
}
return 0;
}