題目鏈接:點擊查看
題目大意:給出一個長度爲 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;
}