2019HDU多校6601 (主席树第k大,斐波拉契)

本文介绍了一种使用主席树数据结构解决区间内最大三角形周长问题的方法。通过预处理和查询,文章详细解释了如何在给定的数值范围内找到能够构成三角形的最大周长,特别关注于避免斐波那契数列导致的无法成形问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题意:给出 n n n个数,查询区间用这些数能组成的最大三角形的周长。

题解:由于给出的数最大范围是 1 e 9 1e9 1e9,而我们已经知道,斐波拉契数列中前两项之和等于第三项,这是构不成三角形的。

所以考虑最坏情况,如果区间内的数刚好构成斐波拉契数列,那么最多到第44项就超过了数据范围,因此在44次循环前如果没有答案,即前44项刚好组成斐波拉契数列,那么后面就一定没有答案。

所以用主席树求区间的第1大,第2大,。。。。第k大判断答案合法性,超过44次没出答案直接break掉。``

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector> 
using namespace std;
#define inf 0x3f3f3f3f

#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x)  x&-x;  
#define debugint(name,x) printf("%s: %d\n",name,x);
#define debugstring(name,x) printf("%s: %s\n",name,x);
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 2e5+5;
const int mod = 1e9+7;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m;
vector<int>v;
struct node{
    int l,r,sum;
}hjt[maxn*40];
int a[maxn],rt[maxn],cnt;

int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
void insert(int l,int r,int pre,int &now,int p){
    hjt[++cnt] = hjt[pre];
    now = cnt;
    hjt[now].sum++;
    if(l == r) return;
    int mid = (l+r)>>1;
    if(p <= mid) insert(l,mid,hjt[pre].l,hjt[now].l,p);
    else insert(mid+1,r,hjt[pre].r,hjt[now].r,p);
}
int query(int l,int r,int L,int R,int k){
    if(l == r) return l;
    int tmp = hjt[hjt[R].l].sum - hjt[hjt[L].l].sum;
    int mid = (l+r)>>1;
    if(k <= tmp) return query(l,mid,hjt[L].l,hjt[R].l,k);
    else return query(mid+1,r,hjt[L].r,hjt[R].r,k-tmp);
}


int main(){
	while(~scanf("%d%d",&n,&m)){
		v.clear();
		mem(rt,0);
		for(int i = 1; i <= n; i++){
			scanf("%d",&a[i]);
			v.push_back(a[i]);
		}
		sort(v.begin(),v.end());
    	v.erase(unique(v.begin(),v.end()),v.end());
		for(int i = 1; i <= n; i++)
        	insert(1,v.size(),rt[i-1],rt[i],getid(a[i]));
        int l,r;
        while(m--){
        	scanf("%d%d",&l,&r);
        	int k = r-l+1;
        	if(k < 3) puts("-1");
			else{
				int ok = 0,cnt = 0;
				int t = k;
				ll x1,x2,x3;
				while(k >= 3){
					x1 = v[query(1,v.size(),rt[l-1],rt[r],t)-1];
					x2 = v[query(1,v.size(),rt[l-1],rt[r],t-1)-1];
					x3 = v[query(1,v.size(),rt[l-1],rt[r],t-2)-1];
					if(x2+x3>x1){
						printf("%lld\n",(ll)(x1+x2+x3));
						ok = 1;
						break;
					}
					t--;
					k--;
					cnt++;
					if(cnt >= 45) break;
				}
				if(!ok) puts("-1");
			}	
    	}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值