操作 显然可以用线段树简单维护,平凡。显然比较困难的是操作一。以下所称“操作”代指操作一。
这个操作乍一看就没有什么可维护性,但是你可以发现对区间 操作的时候,除了
这个点,其余点的值都至少减半,这里就有一个很好的性质,因为你多次操作过后肯定会剩下很多个
,而对
去操作是不会改变其值的,有了这个性质,考虑势能线段树。我们可以考虑暴力操作,维护区间最大值,扫到当前区间最大值的时候如果为
那就直接跳过,考虑如何证明复杂度,显然对于一个点,由于一次对其的修改会使其至少减半,所以对一个点
至多进行
次修改,再加上线段树的复杂度就是
。
代码:
#include<bits/stdc++.h>
#define ll long long
#define db double
#define vec vector
#define pb push_back
#define pll pair<ll,ll>
#define mkp make_pair
#define il inline
#define endl "\n"
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
ll n,q,a[200005];
#define ls (u<<1)
#define rs (u<<1|1)
struct seg{
ll l,r,mx,sum;
}w[800005];
void up(ll u){
w[u].mx=max(w[ls].mx,w[rs].mx);
w[u].sum=w[ls].sum^w[rs].sum;
}
void bd(ll u,ll l,ll r){
w[u].l=l,w[u].r=r;
if(l==r) return w[u].mx=w[u].sum=a[l],void(0);
ll md=(l+r)>>1;
bd(ls,l,md),bd(rs,md+1,r);
up(u);
}
void mdf(ll u,ll l,ll r){
if(w[u].mx<=0) return;
if(w[u].l==w[u].r) return w[u].mx=w[u].sum=(w[u].sum/(w[u].l-l+1)),void(0);
ll md=(w[u].l+w[u].r)>>1;
if(l<=md) mdf(ls,l,r);
if(r>md) mdf(rs,l,r);
up(u);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(ll i=1;i<=n;i++) cin>>a[i];
bd(1,1,n);
while(q--){
ll opt,l,r;
cin>>opt;
if(opt==1){
cin>>l>>r,mdf(1,l,r);
}else{
cout<<w[1].sum<<endl;
}
}
return 0;
}

京公网安备 11010502036488号