这是道数据结构题。
同样的,考虑询问区间为
[
1
,
n
]
[1,n]
[ 1 , n ] 的情形,麻烦的地方在于向左右扩展的顺序性。最简单的想法是,对于每个点,在左右两边分别保留
log
n
\log n
log n 个有用的分界点。这样修改一个位置,只用修改对应的分界点就做完了。最后区间查询最不济可以用二维平面来处理,这道题就做完了。
好像和正解有点出入
上述做法问题在于,无法快速维护分界点的信息。事实上,考虑分治,然后合并左右区间信息。注意到,如果两个位置在右区间扩展得到的极大区间是相同的,那么我们只需要关注这样区间的数量,又因为左端点是固定的,因此本质不同的极大区间不会超过
log
n
\log n
log n 个。而左区间只用把有用的分界点存下来即可。事实上这些分界点可以借助左区间的信息得出。可以用双指针做到
O
(
n
log
2
n
)
O(n\log^2 n)
O ( n log 2 n ) 。
代码稍微有点难写。
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f3f3f3f3f
#define db double
#define cpx complex<db>
using namespace std;
const int N=1e5 +5 ;
int n,m;
ll a[N],s[N];
void add (int x,ll y) {
for (;x<=n;x+=x&-x)s[x]+=y;
}
ll getsum (int l,int r) {
ll res=0 ;
for (int x=r;x;x-=x&-x)res+=s[x];
for (int x=l-1 ;x;x-=x&-x)res-=s[x];
return res;
}
struct node {
vector<pair<int ,int >>vl,vr;
}t[N<<2 ];
int Z;
node merge (node x,node y) {
map<int ,int >vl,vr;
node z;
vector<pair<int ,int >>posl=x.vr,posr=y.vl;
for (int i=0 ;i+1 <x.vl.size ();i++){
vl[x.vl[i].fi]=x.vl[i].se;
}
for (int i=0 ;i+1 <y.vr.size ();i++){
vr[y.vr[i].fi]=y.vr[i].se;
}
int pos=-1 ,pos2=0 ,pos3=0 ;
int l=posl.back ().fi,r=posr.back ().fi,mid=x.vl.back ().fi;
int nowl=mid+1 ,nowr=posr[0 ].fi;
while (1 ){
if (pos+1 <posl.size ()&&getsum (nowl,nowr)>=a[nowl-1 ])pos++,nowl=posl[pos].fi;
else if (pos2+1 <posr.size ()&&getsum (nowl,nowr)>=a[nowr+1 ])pos2++,nowr=posr[pos2].fi;
else {
while (pos3<=pos2){
if (pos+1 ==posl.size ())vl[nowr]+=posr[pos3].se;
if (pos2+1 ==posr.size ())vr[nowl]+=posr[pos3].se;
pos3++;
}
pos2++;
if (pos2==posr.size ())break ;
nowr=posr[pos2].fi;
}
}
pos=0 ,pos2=-1 ,pos3=0 ;
nowl=posl[0 ].fi,nowr=mid;
while (1 ){
if (pos2+1 <posr.size ()&&getsum (nowl,nowr)>=a[nowr+1 ])pos2++,nowr=posr[pos2].fi;
else if (pos+1 <posl.size ()&&getsum (nowl,nowr)>=a[nowl-1 ])pos++,nowl=posl[pos].fi;
else {
while (pos3<=pos){
if (pos+1 ==posl.size ())vl[nowr]+=posl[pos3].se;
if (pos2+1 ==posr.size ())vr[nowl]+=posl[pos3].se;
pos3++;
}
pos++;
if (pos==posl.size ())break ;
nowl=posl[pos].fi;
}
}
for (auto x:vl)z.vl.pb (x);
for (auto x:vr)z.vr.pb (x);
reverse (z.vr.begin (),z.vr.end ());
return z;
}
void build (int p,int l,int r) {
if (l==r){
t[p].vl.pb ({l,1 }),t[p].vr.pb ({l,1 });
return ;
}
int mid=l+r>>1 ;
build (p<<1 ,l,mid),build (p<<1 |1 ,mid+1 ,r);
t[p]=merge (t[p<<1 ],t[p<<1 |1 ]);
}
node query (int p,int l,int r,int ql,int qr) {
if (ql<=l&&r<=qr)return t[p];
int mid=l+r>>1 ;
if (qr<=mid)return query (p<<1 ,l,mid,ql,qr);
if (mid<ql)return query (p<<1 |1 ,mid+1 ,r,ql,qr);
return merge (query (p<<1 ,l,mid,ql,qr),query (p<<1 |1 ,mid+1 ,r,ql,qr));
}
void modify (int p,int l,int r,int x) {
if (l==r)return ;
int mid=l+r>>1 ;
x<=mid?modify (p<<1 ,l,mid,x):modify (p<<1 |1 ,mid+1 ,r,x);
t[p]=merge (t[p<<1 ],t[p<<1 |1 ]);
}
int main () {
ios::sync_with_stdio (false );
cin.tie (0 ),cout.tie (0 );
cin>>n;
for (int i=1 ;i<=n;i++){
cin>>a[i],add (i,a[i]);
}
build (1 ,1 ,n);
cin>>m;
for (int i=1 ;i<=m;i++){
int op,x,y;
cin>>op>>x>>y;
if (op==1 ){
add (x,-a[x]);
a[x]=y,add (x,a[x]);
modify (1 ,1 ,n,x);
}
else {
node res=query (1 ,1 ,n,x,y);
cout<<res.vl.back ().se<<"\n" ;
}
}
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」