題解 三角形
題目描述
具體做法與心路歷程
這道題一眼過去。。。暴力我會!,每次詢問將區間排序,然後貪心從最大的開始匹配,然後一路往下匹配!
然後就沒了。考試時原本想打個莫隊維護來卡一卡,結果忘記怎麼打待修莫隊了~,胡亂對後面 分打了個線段樹,每次選出區間最大值,然後再去掉最大值,一路選下去知道出結果,最後再改回來。然後就了。(莫名來的驚喜)。
具體做法
正解的確是線段樹。
考慮每個的範圍是~,如果區間最大的三條邊不能組成三角形一定滿足,實際上我們反過來考慮有這個關係,那麼就是已知兩條邊,最大不能組成三角形的邊滿足,我們讓,每次把選出來的和原來的看成新的。那麼這個遞推式就成斐波那契數列了。所以如果我們每次取區間最大值,不能組成三角形則繼續取,那麼數值的減小速度是斐波那契數列的增長速度的,約爲,所以我們每次取最大值實際上最多取大概次就會得到結果。
線段樹的複雜度約爲。
考場上的暴力程序也在。懶得改了
/*******************************
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;
}