杭电多校第二场1011[主席树求区间第k大]

本文探讨了一种解决三角形最大周长问题的算法,利用主席树数据结构优化查询过程,实现高效寻找区间内可构成三角形的最大周长。

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

1011 Keen On Everything But Triangle
Keen On Everything But Triangle
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2617 Accepted Submission(s): 578

Problem Description
N sticks are arranged in a row, and their lengths are a1,a2,…,aN.

There are Q querys. For i-th of them, you can only use sticks between li-th to ri-th. Please output the maximum circumference of all the triangles that you can make with these sticks, or print −1 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).

The second line contains N integers, the i-th integer ai(1≤ai≤109) of them showing the length of the i-th stick.

Then follow Q lines. i-th of them contains two integers li,ri(1≤li≤ri≤N), meaning that you can only use sticks between li-th to ri-th.

It is guaranteed that the sum of Ns and the sum of Qs in all test cases are both no larger than 4×105.

Output
For each test case, output Q 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

Source
2019 Multi-University Training Contest 2

题意:有N根木棒,每根长度为ai,有q次询问,每次询问一个区间内能组成的三角形的最大周长
题解:易知结果就是求能组成三角形的第i大和第i+1大和第i+2大之和。主席树求区间第k大每次修改和查询的时间复杂度为logn,针对本题,每次询问给一个区间,需要进行O(n)次查询第k大来判断是否可以构成三角形,那么每次询问复杂度就是O(nlogn),q次就是O(nqlogn),显然超时。但是实际上最坏的情况下:木棒长度构成了斐波那契数列,但是斐波那契数列元素在第40+项的时候就已经超过1e9了,所以复杂度最多为O(50*qlogn)可以通过

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=1e5+5;
struct node{
    int l;
    int r;
    int sum;
}no[maxn*45];
int cnt,root[maxn];
ll a[maxn],b[maxn],ac[55];
void build(int &rt,int l,int r){
    rt=++cnt;
    no[cnt].sum=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(no[cnt].l,l,mid);
    build(no[cnt].r,mid+1,r);
}
void update(int &rt,int l,int r,int last,int v){
    rt=++cnt;
    no[cnt].sum=no[last].sum+1;
    no[cnt].l=no[last].l;
    no[cnt].r=no[last].r;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(mid>=v)update(no[cnt].l,l,mid,no[last].l,v);
    else update(no[cnt].r,mid+1,r,no[last].r,v);
}
int query(int L,int R,int l,int r,int k){
    if(l==r)return l;
    int num=no[no[R].r].sum-no[no[L].r].sum;
    int mid=(l+r)>>1;
    if(num>=k)return query(no[L].r,no[R].r,mid+1,r,k);
    else return query(no[L].l,no[R].l,l,mid,k-num);
}
int main(){
    int n,q;
    while(scanf("%d%d",&n,&q)==2){
        cnt=0;
        for(int i=1;i<=n;i++){scanf("%lld",&a[i]);b[i]=a[i];}
        sort(b+1,b+1+n);
        int siz=unique(b+1,b+1+n)-(b+1);
        for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+siz,a[i])-b;
        build(root[0],1,siz);
        for(int i=1;i<=n;i++)update(root[i],1,siz,root[i-1],a[i]);
        while(q--){
            int c,d;
            scanf("%d%d",&c,&d);
            if(d<c)swap(c,d);
            if(d-c+1<3){printf("-1\n");continue;}
            int maxx=min(50,d-c+1);
            for(int i=1;i<=maxx;i++){
                ac[i]=b[query(root[c-1],root[d],1,siz,i)];
            }
            ll ak=-1;
            for(int i=1;i+2<=maxx;i++){
                if(ac[i]<ac[i+1]+ac[i+2]){
                    ak=ac[i]+ac[i+1]+ac[i+2];
                    break;
                }
            }
            printf("%lld\n",ak);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值