题目:hdu 6601
这个题其实是个很裸的主席树,关键是在复杂度分析。
首先,如果对于一个区间的所有值,我们想去选一个最大周长三角形该怎么选? 因为三角形的周长要最大,我们先把值从大到小排序。用Ki表示第 i 大的边,选出K1,K2,K3,如果K1<K2+K3的话,就能构成三角形且周长最大(K1+K2<K3,K1+K3<K2 必然成立) 如果不能构成三角形,我们思考一下 K1>=K2+K3,如果我们不选K3的话 因为Ki(i>=4) 肯定小于K2,K3 所以Ki和K1,K2必然不能构成三角形,因此我们只能舍弃K1,然后继续选K2,K3,K4构成三角形 这可以O(n) 完成 加上排序的复杂度 整个过程是 nlogn的 但是有q个询问 nqlogn的复杂度必然不行
显然按上述方法 我们找到一个成立的条件就会退出循环不在继续 我们想一下不能成立的极限条件是什么
对于每三个相邻的项(排序后)满足:
也就是斐波拉契数列:1 1 2 3 5 8 13......... 这样的话对于值域为1e9的斐波拉契数列 最多只有44项 也就是说 最多进行44次就能找到答案
那么就有很明显的思路了 对于区间l到r 主席树暴力得到第K大,K-1大,K-2大,再按上述讨论的方法就行了
复杂度接近44*q*logn
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int c[N*30],lson[N*30],rson[N*30],T[N],t[N],a[N];
int n,m,q,tot;
typedef long long ll;
int Hash(int x){
return lower_bound(t+1,t+1+m,x)-t;
}
int update(int rt,int pos,int val){
int newrt=++tot,temp=newrt;
int l=1,r=m;
c[newrt]=c[rt]+val;
while(l<r){
int mid = l+r>>1;
if(pos<=mid){
r=mid;
lson[newrt]=++tot;rson[newrt]=rson[rt];
newrt=lson[newrt];rt=lson[rt];
}else{
l=mid+1;
rson[newrt]=++tot;lson[newrt]=lson[rt];
newrt=rson[newrt];rt=rson[rt];
}
c[newrt]=c[rt]+val;
}
return temp;
}
int query(int l_rt,int r_rt,int k){
int l=1,r=m;
while(l<r){
int mid = l+r>>1;
if(c[lson[r_rt]]-c[lson[l_rt]]>=k){
r=mid;
r_rt=lson[r_rt];l_rt=lson[l_rt];
}else{
k-=c[lson[r_rt]]-c[lson[l_rt]];
l=mid+1;
r_rt=rson[r_rt];l_rt=rson[l_rt];
}
}
return l;
}
int main(){
while(~scanf("%d%d",&n,&q)){
m=tot=0;
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
t[++m]=a[i];
}
sort(t+1,t+1+m);
m=unique(t+1,t+1+m)-t-1;
for(int i = 1; i <= n; i++) T[i]=update(T[i-1],Hash(a[i]),1);
for(int i = 1; i <= q; i++){
int l,r;
scanf("%d%d",&l,&r);
int len = (r-l+1);
ll ans = -1;
while(len>=3){
ll x1,x2,x3;
x1=1ll*t[query(T[l-1],T[r],len)];
x2=1ll*t[query(T[l-1],T[r],len-1)];
x3=1ll*t[query(T[l-1],T[r],len-2)];
if(x1<x2+x3){
ans=x1+x2+x3;
break;
}
len--;
}
printf("%lld\n",ans);
}
}
return 0;
}