題解 三角形

題解 三角形

題目描述

680d63fc73077b0e9e61c.png

_19b523.png

具體做法與心路歷程

這道題一眼過去。。。暴力O(QNlogN)O(QNlogN)我會!,每次詢問將區間排序,然後貪心從最大的開始匹配,然後一路往下匹配!

然後就沒了。考試時原本想打個莫隊維護setset來卡一卡,結果忘記怎麼打待修莫隊了~,胡亂對後面4040 分打了個線段樹,每次選出區間最大值,然後再去掉最大值,一路選下去知道出結果,最後再改回來。然後就ACAC了。(莫名來的驚喜)。

具體做法

正解的確是線段樹。

考慮每個AiA_i的範圍是11~10910^9,如果區間最大的三條邊不能組成三角形一定滿足a+bca+b \leq c,實際上我們反過來考慮有這個關係,那麼就是已知兩條邊a,ba,b,最大不能組成三角形的邊cc滿足a+b=ca+b=c,我們讓a,b=1a,b=1,每次把選出來的cc和原來的bb看成新的a,ba,b。那麼這個遞推式就成斐波那契數列了。所以如果我們每次取區間最大值,不能組成三角形則繼續取,那麼數值的減小速度是\geq斐波那契數列的增長速度的,約爲O(logA)O(logA),所以我們每次取最大值實際上最多取大概4040次就會得到結果。

線段樹的複雜度約爲O(QlogNlogA)O(QlogNlogA)

Code\mathcal{Code}

考場上的暴力程序也在。懶得改了

/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月28日 星期一 16時20分37秒
*******************************/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>

using namespace std;

struct IO{
    template<typename T>
    IO & operator>>(T&res)
    {
        T q=1;char ch;
        while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
        res=(ch^48);
        while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
        res*=q;
        return *this;
    }
}cin;

const int maxn=1e5+10;
int n,q,tot;
long long a[maxn],b[maxn];

bool check(register long long a,register long long b,register long long c)
{
    return a<b+c;
}

/*{{{work*/
void work()
{
    register  int opt,x,y;
    long long ans=0;
    while(q--)
    {
        cin>>opt>>x>>y;
        if(opt==1)
        {
            a[x]=y;
        }
        else
        {
            tot=0;
            for(int i=x;i<=y;i++)
                b[++tot]=a[i];
            ans=0;
            sort(b+1,b+tot+1);
            for(int i=tot;i>=3;i--)
                if(check(b[i],b[i-1],b[i-2]))
                {
                    ans=b[i]+b[i-1]+b[i-2];
                    break;
                }
            printf("%lld\n",ans);
        }
    }
}
/*}}}*/

/*{{{線段樹*/

namespace SegmentTree{

    struct Node{
        long long val;
        int loc;
        bool operator<(const Node & p) const
        {
            return val<p.val;
        }
        Node(long long a=0,int b=0):val(a),loc(b){}
    };

    Node tr[maxn*4];

    inline void update(int k)
    {
        tr[k]=max(tr[k<<1],tr[k<<1|1]);
    }

    void build(register int k,register int l,register int r)
    {
        if(l==r)
        {
            tr[k]=Node(a[l],l);
            return;
        }
        register int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        update(k);
    }

    inline void modify(register int k,register int l,register int r,register int pos,register long long val)
    {
        if(l==r)
        {
            tr[k].val=val;
            return;
        }
        register int mid=(l+r)>>1;
        if(pos<=mid)
            modify(k<<1,l,mid,pos,val);
        else
            modify(k<<1|1,mid+1,r,pos,val);
        update(k);
    }

    Node query(register int k,register int l,register int r,register int x,register int y)
    {
        if(l>=x && r<=y) return tr[k];
        if(l>y  ||  r<x) return Node(-1,-1);
        register int mid=(l+r)>>1;
        return max(query(k<<1,l,mid,x,y),query(k<<1|1,mid+1,r,x,y));
    }

};

/*}}}*/

int _top;
SegmentTree::Node stk[maxn];

void solve()
{
    SegmentTree::build(1,1,n);
    register int opt,x,y;
    while(q--)
    {
        cin>>opt>>x>>y;
        if(opt==1)
        {
            SegmentTree::modify(1,1,n,x,y);
        }
        else
        {
            register long long ans=0;
            register int len=y-x+1;
            _top=0;
            while(_top<=len)
            {
                stk[++_top]=SegmentTree::query(1,1,n,x,y);
                SegmentTree::modify(1,1,n,stk[_top].loc,-1);
                if(_top>=3 && check(stk[_top-2].val,stk[_top-1].val,stk[_top].val))
                {
                    ans=stk[_top].val+stk[_top-1].val+stk[_top-2].val;
                    break;
                }
            }
            for(register int i=1;i<=_top;i++)
                SegmentTree::modify(1,1,n,stk[i].loc,stk[i].val);
            printf("%lld\n",ans);
        }
    }
}

int main()
{
    //freopen("triangle.in","r",stdin);
    //freopen("triangle.out","w",stdout);
    cin>>n>>q;
    for(register int i=1;i<=n;i++)
        cin>>a[i];
    if(n<=1000)
    {
        work();
    }
    else
    {
        solve();
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章