1011:http://acm.hdu.edu.cn/showproblem.php?pid=6601
题意:给你n个数,q次询问,每次询问一个区间[l,r]表示只能从[l,r]区间里选最大的能构成三角形的三条边,输出其最大周长。
分析:一看肯定说用线段树维护,但。。。。。比赛时想了好久不知道维护什么,甚至还不顾莫队的T飞的复杂度交了几发。
维护一个区间的45个最大值,这样一定能找到周长最大的三角形,因为斐波拉契数列f[45]>1e9,如果45个最大值都试完了还找不到三角形则肯定不存在。最坏的情况也就是区间的数刚好是斐波拉契数列。
然后再线段树区间合并就行了,合并时采用有序表的合并方法,复杂度O(45+45),同时还可以加上一些优化,比如如果已经找到了满足条件的最大三条边就不用再往下找较小的满足条件的边了,因为它们已经没用了(就算那些较小的边可以和其他子树的边合并也不会大于刚刚找的满足条件的最大三条边)。
Ac code:(查询未优化 2200ms)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+1;
int a[maxn];
struct Tree{
int d[46];
int k;
Tree(int k=0):k(k){}
inline Tree Merge(const Tree& a,const Tree& b)
{
Tree res;
int i=1,j=1;
while(i<=a.k&&j<=b.k)
{
if(res.k>=45) return res;
if(a.d[i]<=b.d[j]){
res.d[++res.k]=b.d[j];
j++;
}
else{
res.d[++res.k]=a.d[i];
i++;
}
if(res.k>=3&&res.d[res.k]+res.d[res.k-1]>res.d[res.k-2]) return res;
}
while(i<=a.k){
if(res.k>=45) return res;
res.d[++res.k]=a.d[i++];
if(res.k>=3&&res.d[res.k]+res.d[res.k-1]>res.d[res.k-2]) return res;
}
while(j<=b.k){
if(res.k>=45) return res;
res.d[++res.k]=b.d[j++];
if(res.k>=3&&res.d[res.k]+res.d[res.k-1]>res.d[res.k-2]) return res;
}
return res;
}
}tree[maxn<<2];
void pushup(int rt)
{
tree[rt]=tree[rt].Merge(tree[rt<<1],tree[rt<<1|1]);
}
void buildtree(int rt,int l,int r)
{
if(l==r){
tree[rt].d[1]=a[l];
tree[rt].k=1;
return;
}
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
pushup(rt);
}
Tree query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R){
return tree[rt];
}
Tree ans;
int mid=(l+r)>>1;
if(mid>=L) ans=ans.Merge(ans,query(rt<<1,l,mid,L,R));
if(mid<R) ans=ans.Merge(ans,query(rt<<1|1,mid+1,r,L,R));
return ans;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
buildtree(1,1,n);
int l,r;
while(m--){
scanf("%d%d",&l,&r);
if(r-l+1<3){
puts("-1");
continue;
}
Tree cnt=query(1,1,n,l,r);
ll ans=-1;
for(int i=1;i<=cnt.k-2;i++)
{
if(cnt.d[i+1]+cnt.d[i+2]>cnt.d[i]){
ans=1ll*cnt.d[i+1]+1ll*cnt.d[i+2]+1ll*cnt.d[i];
break;
}
}
printf("%lld\n",ans);
}
}
return 0;
}
查询优化 920ms:
///920ms
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+1;
int a[maxn];
struct Tree
{
int d[46];
int k;
void init()
{
k=0;
for(int i=1; i<=45; i++) d[i]=0;
}
inline Tree Merge(const Tree& a,const Tree& b)
{
Tree res;
res.k=0;
int i=1,j=1;
while(i<=a.k&&j<=b.k)
{
if(res.k>=45) return res;
if(a.d[i]<=b.d[j])
{
res.d[++res.k]=b.d[j];
j++;
}
else
{
res.d[++res.k]=a.d[i];
i++;
}
if(res.k>=3&&res.d[res.k]+res.d[res.k-1]>res.d[res.k-2]) return res;
}
while(i<=a.k)
{
if(res.k>=45) return res;
res.d[++res.k]=a.d[i++];
if(res.k>=3&&res.d[res.k]+res.d[res.k-1]>res.d[res.k-2]) return res;
}
while(j<=b.k)
{
if(res.k>=45) return res;
res.d[++res.k]=b.d[j++];
if(res.k>=3&&res.d[res.k]+res.d[res.k-1]>res.d[res.k-2]) return res;
}
return res;
}
} tree[maxn<<2];
void pushup(int rt)
{
tree[rt]=tree[rt].Merge(tree[rt<<1],tree[rt<<1|1]);
}
void buildtree(int rt,int l,int r)
{
if(l==r)
{
tree[rt].d[1]=a[l];
tree[rt].k=1;
return;
}
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
pushup(rt);
}
ll ans[46],tmp[46];
int len;
void query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
int tlen=len;
for(int i=1; i<=len; i++) tmp[i]=ans[i];
int i=1,j=1;
len=0;
while(i<=tree[rt].k&&j<=tlen&&len<45)
{
if(tree[rt].d[i]<tmp[j])
ans[++len]=tmp[j++];
else
ans[++len]=tree[rt].d[i++];
if(len>=3&&ans[len]+ans[len-1]>ans[len-2]) return;
}
while(i<=tree[rt].k&&len<45)
{
ans[++len]=tree[rt].d[i++];
if(len>=3&&ans[len]+ans[len-1]>ans[len-2]) return;
}
while(j<=tlen&&len<45)
{
ans[++len]=tmp[j++];
if(len>=3&&ans[len]+ans[len-1]>ans[len-2]) return;
}
return;
}
int mid=(l+r)>>1;
if(mid>=L) query(rt<<1,l,mid,L,R);
if(mid<R) query(rt<<1|1,mid+1,r,L,R);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
buildtree(1,1,n);
int l,r;
while(m--)
{
scanf("%d%d",&l,&r);
if(r-l+1<3)
{
puts("-1");
continue;
}
len=0;
query(1,1,n,l,r);
ll res=-1;
for(int i=1; i<=len-2; i++)
if(ans[i+1]+ans[i+2]>ans[i])
{
res=ans[i+1]+ans[i+2]+ans[i];
break;
}
printf("%lld\n",res);
}
}
return 0;
}