题解 三角形
题目描述
具体做法与心路历程
这道题一眼过去。。。暴力 O ( Q N l o g N ) O(QNlogN) O(QNlogN)我会!,每次询问将区间排序,然后贪心从最大的开始匹配,然后一路往下匹配!
然后就没了。考试时原本想打个莫队维护 s e t set set来卡一卡,结果忘记怎么打待修莫队了~,胡乱对后面 40 40 40 分打了个线段树,每次选出区间最大值,然后再去掉最大值,一路选下去知道出结果,最后再改回来。然后就 A C AC AC了。(莫名来的惊喜)。
具体做法
正解的确是线段树。
考虑每个 A i A_i Ai的范围是 1 1 1~ 1 0 9 10^9 109,如果区间最大的三条边不能组成三角形一定满足 a + b ≤ c a+b \leq c a+b≤c,实际上我们反过来考虑有这个关系,那么就是已知两条边 a , b a,b a,b,最大不能组成三角形的边 c c c满足 a + b = c a+b=c a+b=c,我们让 a , b = 1 a,b=1 a,b=1,每次把选出来的 c c c和原来的 b b b看成新的 a , b a,b a,b。那么这个递推式就成斐波那契数列了。所以如果我们每次取区间最大值,不能组成三角形则继续取,那么数值的减小速度是 ≥ \geq ≥斐波那契数列的增长速度的,约为 O ( l o g A ) O(logA) O(logA),所以我们每次取最大值实际上最多取大概 40 40 40次就会得到结果。
线段树的复杂度约为 O ( Q l o g N l o g A ) O(QlogNlogA) O(QlogNlogA)。
C o d e \mathcal{Code} 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;
}