[Ynoi2007] rgxsxrs 题解
Description
用一个数据结构维护一个序列 \(a_i\) ,使得能够:
1.将一个区间内所有大于一个数(设为 \(x\) )的值全部减去这个数
2.求一个区间的和,最大值和最小值
\(1\leq n,m\leq 5\cdot 10^5\ \ \ 1\leq a_i\leq 10^9\)
Solution
大佬们有说分块套 splay 可以过,但是我做不来,所以还是来讲一讲比较普遍的做法吧。。
首先,对于维护一个序列,我们应该能比较容易能够想到用线段树去维护区间。
然后在此基础上,我们看看怎么去暴力修改,
当我们搜到一个区间的时候,会分三种情况:
1.如果最大值都比 \(x\) 小,直接跳过;
2.如果最小值都比 \(x\) 大,打个懒标记就跑;
3.就是其他的情况,有大的,有小的,就只能递归下去,最终一直到前两种的其中一种情况;
如果我们这么来看,时间复杂度要废,就比如每次给定的 \(x\) 能让整个区间交替着一大一小,那么每次递归都会到叶子节点,所以直接硬上约等于暴力,考虑可以怎么解决。
从值域出发,考虑对值域分块,但直接上 \(10^9\) 的分块似乎不太有用,但指数的爆炸性增长可以解决。所以我们可以考虑按照 \([w^k,w^{k+1})\) 这样来分块.
这样只对值域在这一块的值进行上面的操作,就不会出现无限细分的情况。
然后注意操作完后可能有些值会向更小的块掉落,但最坏可能都是 \(\log\) 级别的,时间复杂度上就解决了。
但是,这样做空间是 \(n\cdot \log\) 级别的,善(du)良(liu)的出题人只给了我们 64MB ,所以我们还得来优化一下空间。
想到叶子节点的利用率比较低,甚至可以暴力操作,所以我们可以不存线段树中长度小于 \(k\) 的序列,从而直接暴力,以比较小代价的时间换取空间。
至此,我们以线性的空间完成了这道题。
注:这里面 \(w\) 我取了 \(16\) , \(K\) 取了 \(32\) ,当然其他的 \(w\) 和 \(k\) 都各有千秋,这个看自己怎么取。
#include<bits/stdc++.h>
#define num(id,x) seg[id].num[x]
#define sum(id,x) seg[id].sum[x]
#define lzy(id,x) seg[id].lzy[x]
#define imax(id,x) seg[id].imax[x]
#define imin(id,x) seg[id].imin[x]
#define lt(id) seg[id].lt
#define rt(id) seg[id].rt
using namespace std;
typedef long long ll;
const int N=5e5+10,M=4e4+10,W=16,K=32;
const int INF=2e9,last=(1<<20);
int n,m,a[N],lastans,maxx,minn;
ll ans;
struct mdzz{
ll num[M],sum[M],lzy[M],lt,rt;
int imax[M],imin[M];
}seg[9];
inline ll read(){
ll s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
inline void print(ll x){
if(x<0){
x=-x;
putchar('-');
}
if(x>9)print(x/10);
putchar(x%10+48);
}
inline int belong(ll x){
int now=1;
while(x>rt(now))++now;
return now;
}
inline void pushup_blo(int it,int now,int lf,int rg){
num(it,now)=sum(it,now)=imax(it,now)=0;
imin(it,now)=INF;
for(int i=lf;i<=rg;++i){
if(lt(it)<=a[i]&&a[i]<=rt(it)){
++num(it,now);
sum(it,now)+=a[i];
imax(it,now)=max(imax(it,now),a[i]);
imin(it,now)=min(imin(it,now),a[i]);
}
}
}
inline void pushdown_blo(int it,int lf,int rg,ll val){
for(int i=lf;i<=rg;++i){
if(lt(it)<=a[i]&&a[i]<=rt(it))a[i]-=val;
}
}
inline void pushup(int it,int now){
num(it,now)=num(it,now<<1)+num(it,now<<1|1);
sum(it,now)=sum(it,now<<1)+sum(it,now<<1|1);
imax(it,now)=max(imax(it,now<<1),imax(it,now<<1|1));
imin(it,now)=min(imin(it,now<<1),imin(it,now<<1|1));
}
inline void pushdown(int it,int now){
if(lzy(it,now)){
if(num(it,now<<1)){
lzy(it,now<<1)+=lzy(it,now);
imax(it,now<<1)-=lzy(it,now);
imin(it,now<<1)-=lzy(it,now);
sum(it,now<<1)-=lzy(it,now)*num(it,now<<1);
}
if(num(it,now<<1|1)){
lzy(it,now<<1|1)+=lzy(it,now);
imax(it,now<<1|1)-=lzy(it,now);
imin(it,now<<1|1)-=lzy(it,now);
sum(it,now<<1|1)-=lzy(it,now)*num(it,now<<1|1);
}
lzy(it,now)=0;
}
}
inline void insert(int it,int now,int lf,int rg,int pos,int val){
if(lf+K>rg){
if(lzy(it,now)){
pushdown_blo(it,lf,rg,lzy(it,now));
lzy(it,now)=0;
}
a[pos]=val;
pushup_blo(it,now,lf,rg);
return ;
}
int mid=(lf+rg)>>1;
pushdown(it,now);
if(pos<=mid)insert(it,now<<1,lf,mid,pos,val);
else insert(it,now<<1|1,mid+1,rg,pos,val);
pushup(it,now);
}
inline void update_blo(int it,int lf,int rg,int lef,int rig,int val){
int left=max(lf,lef),rigt=min(rg,rig);
for(int i=left;i<=rigt;++i){
if(lt(it)<=a[i]&&a[i]<=rt(it)&&a[i]>val){
a[i]-=val;
if(a[i]<lt(it))insert(belong(a[i]),1,1,n,i,a[i]);
}
}
}
inline void query_blo(int it,int lf,int rg,int lef,int rig){
int left=max(lf,lef),rigt=min(rg,rig);
for(int i=left;i<=rigt;++i){
if(lt(it)<=a[i]&&a[i]<=rt(it)){
ans+=a[i];
maxx=max(maxx,a[i]);
minn=min(minn,a[i]);
}
}
}
inline void update(int it,int now,int lf,int rg,int lef,int rig,int val){
if(imax(it,now)<=val)return ;
if(lf+K>rg){
if(lzy(it,now)){
pushdown_blo(it,lf,rg,lzy(it,now));
lzy(it,now)=0;
}
update_blo(it,lf,rg,lef,rig,val);
pushup_blo(it,now,lf,rg);
return ;
}
if(lef<=lf&&rg<=rig){
if(lt(it)+val<=imin(it,now)){
lzy(it,now)+=val;
imax(it,now)-=val;
imin(it,now)-=val;
sum(it,now)-=val*num(it,now);
return ;
}
}
int mid=(lf+rg)>>1;
pushdown(it,now);
if(lef<=mid)update(it,now<<1,lf,mid,lef,rig,val);
if(rig>mid)update(it,now<<1|1,mid+1,rg,lef,rig,val);
pushup(it,now);
}
inline void query(int it,int now,int lf,int rg,int lef,int rig){
if(lef<=lf&&rg<=rig){
ans+=sum(it,now);
maxx=max(maxx,imax(it,now));
minn=min(minn,imin(it,now));
return ;
}
if(lf+K>rg){
if(lzy(it,now)){
pushdown_blo(it,lf,rg,lzy(it,now));
lzy(it,now)=0;
}
query_blo(it,lf,rg,lef,rig);
pushup_blo(it,now,lf,rg);
return ;
}
int mid=(lf+rg)>>1;
pushdown(it,now);
if(lef<=mid)query(it,now<<1,lf,mid,lef,rig);
if(rig>mid)query(it,now<<1|1,mid+1,rg,lef,rig);
pushup(it,now);
}
int main(){
n=read();m=read();
for(int i=1;i<=8;++i){
lt(i)=rt(i-1)+1;rt(i)=lt(i)*W-1;
for(int j=0;j<M;++j){
imax(i,j)=0;imin(i,j)=INF;
}
}
for(int i=1;i<=n;++i){
a[i]=read();
insert(belong(a[i]),1,1,n,i,a[i]);
}
for(int i=1;i<=m;++i){
int opt=read(),l=read()^lastans,r=read()^lastans;
if(opt==1){
int x=read()^lastans;
for(int j=1;j<=8;++j)if(rt(j)>=x){
update(j,1,1,n,l,r,x);
}
}
else if(opt==2){
ans=maxx=0;minn=INF;
for(int j=1;j<=8;++j){
query(j,1,1,n,l,r);
}
print(ans);printf(" ");
print(minn);printf(" ");
print(maxx);printf("\n");
lastans=ans%last;
}
}
return 0;
}