2023牛客暑期多校训练营8-C Clamped Sequence II
https://ac.nowcoder.com/acm/contest/57362/C
文章目录
- 2023牛客暑期多校训练营8-C Clamped Sequence II
- 题意
- 解题思路
- 代码
题意
解题思路
先考虑不加紧密度的情况,要支持单点修改,整体查询,可以用值域线段树来求。设
t
r
e
e
[
x
]
.
n
u
m
tree[x].num
tree[x].num表示数值在
[
l
,
r
]
[l,r]
[l,r]区间的数的个数,
t
r
e
e
[
x
]
.
s
u
m
tree[x].sum
tree[x].sum表示数值在
[
l
,
r
]
[l,r]
[l,r]区间的数的总和,
t
r
e
e
[
x
]
.
a
n
s
tree[x].ans
tree[x].ans表示数值在
[
l
,
r
]
[l,r]
[l,r]区间的数的紧密度,结合下图,可以求得转移式:
n
u
m
x
=
n
u
m
l
s
o
n
+
n
u
m
r
s
o
n
s
u
m
x
=
n
u
m
l
s
o
n
+
s
u
m
r
s
o
n
a
n
s
x
=
a
n
s
l
s
o
n
+
a
n
s
r
s
o
n
+
s
u
m
r
s
o
n
×
n
u
m
l
s
o
n
−
s
u
m
l
s
o
n
×
n
u
m
r
s
o
n
num_x=num_{lson}+num_{rson}\\ sum_x=num_{lson}+sum_{rson}\\ ans_x=ans_{lson}+ans_{rson}+sum_{rson}\times num_{lson}-sum_{lson}\times num_{rson}
numx=numlson+numrsonsumx=numlson+sumrsonansx=anslson+ansrson+sumrson×numlson−sumlson×numrson
此时我们加入紧凑的设定,对于每一对确定的
[
l
,
r
]
[l,r]
[l,r]我们都可以算出此时的答案:
a
n
s
w
e
r
=
a
n
s
l
,
r
+
s
u
m
[
l
,
r
]
×
(
n
u
m
[
1
,
l
−
1
]
−
n
u
m
[
r
+
1
,
n
]
)
+
(
n
u
m
[
1
,
l
−
1
]
+
n
u
m
[
l
,
r
]
)
×
n
u
m
[
r
+
1
,
n
]
−
(
n
u
m
[
r
+
1
,
n
]
+
n
u
m
[
l
,
r
]
)
×
n
u
m
[
1
,
l
−
1
]
answer=ans_{l,r}+sum_{[l,r]}\times(num_{[1,l-1]}-num_{[r+1,n]})+(num_{[1,l-1]}+num_{[l,r]})\\ \times num_{[r+1,n]}-(num_{[r+1,n]}+num_{[l,r]})\times num_{[1,l-1]}
answer=ansl,r+sum[l,r]×(num[1,l−1]−num[r+1,n])+(num[1,l−1]+num[l,r])×num[r+1,n]−(num[r+1,n]+num[l,r])×num[1,l−1]
根据出题人所说,该答案是严格单峰的,所以可以用三分求解,但经过我实践却不太像,需要将三分的范围约束在最中间的数
±
d
\pm d
±d再加上左右游移
2
∼
3
2\sim 3
2∼3个数,大致能求出正确答案。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5,M=1e6+5;
ll n,a[N],b[M],q;
struct node{
ll num,l,r;
ll sum,ans;
node operator +(const node a){
node t;
t.num=num+a.num,t.sum=sum+a.sum;
t.ans=num*a.sum-sum*a.num+ans+a.ans;
t.l=l,t.r=a.r;
return t;
}
};
struct tree{
node tr[M<<2];
void build(int res,int l,int r){
tr[res].l=l,tr[res].r=r;
if(l==r){
tr[res].num=b[l],tr[res].sum=b[l]*l;
return;
}
int mid=l+r>>1;
build(res<<1,l,mid);
build(res<<1|1,mid+1,r);
tr[res]=tr[res<<1]+tr[res<<1|1];
}
void add(int res,int x,ll d){
int l=tr[res].l,r=tr[res].r;
if(l==r&&l==x){
tr[res].sum+=d*l;
tr[res].num+=d;
return;
}
int mid=l+r>>1;
if(x<=mid)add(res<<1,x,d);
else add(res<<1|1,x,d);
tr[res]=tr[res<<1]+tr[res<<1|1];
return;
}
node query(int res,int x,int y){
if(x>y)return node{0,0,0,0,0};
int l=tr[res].l,r=tr[res].r;
if(x<=l&&y>=r){
return tr[res];
}
int mid=l+r>>1;
if(y<=mid)return query(res<<1,x,y);
if(x>mid)return query(res<<1|1,x,y);
return query(res<<1,x,y)+query(res<<1|1,x,y);
}
int kth(int id,int l,int r,int k)
{
if(l==r) return l;
int mid=l+r>>1;
if(tr[id<<1].num>=k) return kth(id<<1,l,mid,k);
else return kth(id<<1|1,mid+1,r,k-tr[id<<1].num);
}
}t;
ll f(int l,int d){
int r=l+d;
node p=t.query(1,l,r);
ll num1=p.num,ans1=p.ans,sum1=p.sum;
ll numl=t.query(1,1,l-1).num,numr=t.query(1,r+1,M-1).num;
return ans1-numl*(numr+num1)*l+numr*(numl+num1)*r+sum1*(numl-numr);
}
ll work(int d){
int k=t.kth(1,1,M-1,n+1>>1);
int l=max(1,k-d),r=min(M-1,k+d);
ll ma=0;
while(l+2<=r){
int mi1=(r-l)/3+l,mi2=r-(r-l)/3;
ll ma1=f(mi1,d),ma2=f(mi2,d);
ma=max(ma,max(ma1,ma2));
if(ma1>=ma2)r=mi2-1;
else l=mi1+1;
}
for(int i=l;i<=r;i++)
ma=max(ma,f(i,d));
return ma;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i],b[a[i]]++;
t.build(1,1,M-1);
while(q--){
int op;
cin>>op;
if(op==1){
int x,d;
cin>>x>>d;
t.add(1,a[x],-1);
t.add(1,d,1);
a[x]=d;
}else{
int d;
cin>>d;
cout<<work(d)<<'\n';
}
}
}