题意:长度为n的数列a,Q次操作.
操作1:给出(pos,x) 令a[pos]=x
操作2:给出[L,R] 问(a[L],a[L+1]..a[R]) 能组成的三角形中周长最长的为多少?
n,Q<=1e5,a[i]<=1e9.
先来一个暴力的解法:
对每个询问,枚举当前区间[l,r]第i个数作为最大值时,
因为三角形两边之和要大于第三边,所以剩下两个边在小于a[i]的情况下,显然越大越好.
对当前区间排个序 枚举一下即可 O(Q*nlogn)
对于询问的一个区间,因为周长要最长,所以按最大值从大到小的枚举最长边.
若有解,则立即退出.
否则,说明a[i]>=a[i+1]+a[i+2] 若一直无法组成三角形 则a[i]将以斐波那契数列的增长速度递减下去.
因为1<=a[i]<=1e9 枚举最大值的次数最多为k=50次.
要实现单点更新和区间第k大值的查询.若用权值线段树,a[i]较大还要在离散化一下.
因为要一个节点的前K大 这个信息显然可以合并
操作1:给出(pos,x) 令a[pos]=x
操作2:给出[L,R] 问(a[L],a[L+1]..a[R]) 能组成的三角形中周长最长的为多少?
n,Q<=1e5,a[i]<=1e9.
先来一个暴力的解法:
对每个询问,枚举当前区间[l,r]第i个数作为最大值时,
因为三角形两边之和要大于第三边,所以剩下两个边在小于a[i]的情况下,显然越大越好.
对当前区间排个序 枚举一下即可 O(Q*nlogn)
对于询问的一个区间,因为周长要最长,所以按最大值从大到小的枚举最长边.
若有解,则立即退出.
否则,说明a[i]>=a[i+1]+a[i+2] 若一直无法组成三角形 则a[i]将以斐波那契数列的增长速度递减下去.
因为1<=a[i]<=1e9 枚举最大值的次数最多为k=50次.
要实现单点更新和区间第k大值的查询.若用权值线段树,a[i]较大还要在离散化一下.
因为要一个节点的前K大 这个信息显然可以合并
每个节点合并花费时间为K,每次查询和更新最多logn次合并.直接用线段树搞搞即可.O(Q*K*logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,K=51;
int n;
ll a[N];
struct node{
vector<ll> v;
int l,r;
}t[N<<2];
vector<ll> Merge(vector<ll> a,vector<ll> b)
{
vector<ll> c;
int i=0,j=0;
while(i<a.size()&&j<b.size()&&c.size()<K)
{
if(a[i]>=b[j])
c.push_back(a[i]),i++;
else
c.push_back(b[j]),j++;
}
if(c.size()<K)
{
while(i<a.size()&&c.size()<K)
c.push_back(a[i]),i++;
while(j<b.size()&&c.size()<K)
c.push_back(b[j]),j++;
}
return c;
}
void push_up(int o)
{
t[o].v=Merge(t[o<<1].v,t[o<<1|1].v);
}
void build(int o,int l,int r)
{
t[o].l=l,t[o].r=r;
if(l==r)
{
t[o].v.push_back(a[l]);
return;
}
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
push_up(o);
}
void update(int o,int pos,ll val)
{
int l=t[o].l,r=t[o].r,mid=l+r>>1;
if(l==r)
{
t[o].v.clear();
t[o].v.push_back(val);
return;
}
if(pos<=mid)
update(o<<1,pos,val);
else
update(o<<1|1,pos,val);
push_up(o);
}
vector<ll> query(int o,int ql,int qr)
{
vector<ll> res;
int l=t[o].l,r=t[o].r;
if(l>=ql&&r<=qr)
return t[o].v;
int mid=l+r>>1;
if(ql<=mid)
res=Merge(res,query(o<<1,ql,qr));
if(qr>mid)
res=Merge(res,query(o<<1|1,ql,qr));
return res;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
int Q,op;
ll l,r,x;
cin>>n>>Q;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(Q--)
{
cin>>op>>l>>r;
if(op==1)
update(1,l,r);
else
{
ll ans=0;
vector<ll> res=query(1,l,r);
for(int i=0;i+2<res.size();i++)
{
ll x=res[i],y=res[i+1],z=res[i+2];
if(y+z>x)
{
ans=x+y+z;
break;
}
}
cout<<ans<<'\n';
}
}
return 0;
}
本文介绍了一种使用线段树数据结构解决特定三角形周长问题的方法。通过对给定数列进行操作,包括数值更新和查询指定区间内能构成的最大三角形周长。采用线段树优化查询效率,并讨论了实现细节。
700

被折叠的 条评论
为什么被折叠?



