HDOJ_Multi_school Day 2 T11 Keen On Everything But Triangle

本文探讨了一个将主席树和斐波那契数列结合的算法问题,通过解决最大三角形周长查询,展示了线段树、权值线段树和主席树的应用技巧。

title: HDOJ_Multi_school Day 2 T11
date: 2019-07-28 12:40:00
tags: [HDOJ_Multi_chool,solved,done]
mathjax: true
toc: true

这题主要是对主席树的考察

需要的知识:
线段树(Segment Tree)
权值线段树,主席树,
斐波那契数列(Fibonacci sequence)

Keen On Everything But Triangle

Problem Description

NNN sticks are arranged in a row, and their lengths are a1,a2,...,aNa_1,a_2,...,a_Na1,a2,...,aN.

There are QQQ querys. For i−thi-thith of them, you can only use sticks between li−thl_i-thlith to ri−thr_i-thrith. Please output the maximum circumference of all the triangles that you can make with these sticks, or print −1−11 denoting no triangles you can make.

Input

There are multiple test cases.

Each case starts with a line containing two positive integers N,Q(N,Q≤105)N,Q( N,Q \leq 10^5)N,Q(N,Q105).

The second line contains NNN integers, the i−thi-thith integer ai(1≤ai≤109)a_i(1 \leq a_i \leq 10^9)ai(1ai109) of them showing the length of the i−thi-thith stick.

Then follow $Q $lines. i−thi-thith of them contains two integers li,ri(1≤li≤ri≤N)l_i,r_i(1 \leq l_i \leq r_i \leq N)li,ri(1liriN), meaning that you can only use sticks between li−thl_i-thlith to ri−thr_i-thrith.

It is guaranteed that the sum of NsN_sNs and the sum of QsQ_sQs in all test cases are both no larger than 4×1054×10^54×105.

Output

For each test case, output QQQ lines, each containing an integer denoting the maximum circumference.

Sample Input

5 3
2 5 6 5 2
1 3
2 4
2 5

Sample Output

13
16
16

想法

这题非常巧妙地将主席树和斐波那契数列结合在了一起

首先要求三条边构成三角形就意味着 a+b>ca+b>ca+b>c , 想到 a+b=ca+b=ca+b=c 就是斐波那契兔子数列,再看范围得知最多到数列的第45项

这样为题就装换为求区间最大值、次大值、次次大值、次次次大值…

求区间第K大值,这个在就是主席树的模板题了。

The Code Of My Program

/*
*@Author:   ChenShou
*@Language: C++
*/
//#include <bits/stdc++.h>
#include<iostream>// 
#include<algorithm>//
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>//
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>

//#define DEBUG
#define RI register int
#define endl "\n"

using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-9;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+3;

ll  cnt,root[maxn],a[maxn];
vector<int>v;
struct node{ll l,r,sum;}T[maxn*40];
ll getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}

void update(ll l,ll r,ll &x,ll y,ll pos){
	T[++cnt]=T[y],T[cnt].sum++,x=cnt;
	if(l==r)return;
	ll mid=(l+r)>>1;
	if(mid>=pos)update(l,mid,T[x].l,T[y].l,pos);
	else update(mid+1,r,T[x].r,T[y].r,pos);
}

ll query(ll l,ll r,ll x,ll y,ll k){
	if(l==r)return l ;
	ll mid=(l+r)>>1;
	ll sum=T[T[y].l].sum-T[T[x].l].sum;
	if(sum>=k)return query(l,mid,T[x].l,T[y].l,k);
	else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}
int main(){
#ifdef DEBUG
    freopen("input.in", "r", stdin);
    //freopen("output.out", "w", stdout);
#endif
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    //scanf("%d",&t);
    //while(t--){
    //}
	ll n,m;
    while(scanf ( "%lld %lld" , &n , &m )!=EOF){
    	
    ll t,x,y,k;
    v.clear();cnt = 0;
    for( ll i = 1 ; i <= n ; i++ ){scanf ( "%lld" , & a[i] ),v.push_back(a[i]);}
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for( ll i = 1 ; i <= n ; i++ ){
    	update ( 1 , n , root[i] , root[i-1] , getid(a[i])) ; 
    }
    for( ll i = 1 ; i <= m ; i++ ){
    	int flag=0;
    	ll a,b,c;
    	scanf ( "%lld %lld" , &x , &y ) ; 
    	for(ll i=y-x+1;i>=3;i--){
			 a=v[ query ( 1 , n , root[x-1] , root[y] , i ) - 1 ];
    		 b=v[ query ( 1 , n , root[x-1] , root[y] , i-1 ) - 1 ];
   			 c=v[ query ( 1 , n , root[x-1] , root[y] , i-2 ) - 1 ];
    		if(b+c>a){
    			flag=1;
    			break;
    		}
    	}   
		if(flag)printf("%lld\n",a+b+c);
		else printf("-1\n");
    }
    
	}
#ifdef DEBUG
    printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值