HDU - 6601 Keen On Everything But Triangle(主席树)

题目链接:点击查看

题目大意:给出一个长度为 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;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/106913758