@xiaoziyao
2021-08-14T22:20:32.000000Z
字数 2389
阅读 929
解题报告
loj#6507. 「雅礼集训 2018 Day7」A解题报告:
给定一个长为 的序列, 次操作,支持区间或,区间与,区间求最小值。()
线段树+势能分析。
考虑线段树每个结点记录区间的与值 ,或值 ,最小值 ,然后分类讨论。
与 操作:
或 操作:
有一个小问题,为什么第二种情况可以这样判,比如如果与操作的时候有某一位 没有,可是这个区间的这一位并不相同,那这样不就有问题吗?但是这种情况这些位置都会变成 。(是不是只有我有这么傻逼的问题)
我们想一想怎么证明复杂度。
如果当前递归到了操作区间内,那么一次操作会产生的影响:让区间若干个不同色位集体变成同色,或者集体某一位异或 ,第二种情况小号的复杂度应该与第一种情况是一致的,第一种情况的复杂度应该是 ,所以复杂度是两个 的。
《15min rush 2k 代码》
#include<stdio.h>
#define lc(x) (x)<<1
#define rc(x) (x)<<1|1
const int maxn=500005,maxt=maxn<<2,inf=2147483647;
int n,m;
int a[maxn],vand[maxt],vor[maxt],minn[maxt],lazy[maxt];
inline int min(int a,int b){
return a<b? a:b;
}
inline void pushup(int now){
vand[now]=vand[lc(now)]&vand[rc(now)];
vor[now]=vor[lc(now)]|vor[rc(now)];
minn[now]=min(minn[lc(now)],minn[rc(now)]);
}
inline void getlazy(int now,int v){
vand[now]=vor[now]=minn[now]=lazy[now]=v;
}
inline void pushdown(int now){
if(lazy[now]!=-1)
getlazy(lc(now),lazy[now]),getlazy(rc(now),lazy[now]),lazy[now]=-1;
}
void build(int l,int r,int now){
lazy[now]=-1;
if(l==r){
getlazy(now,a[l]);
return ;
}
int mid=(l+r)>>1;
build(l,mid,lc(now)),build(mid+1,r,rc(now));
pushup(now);
}
void updateand(int l,int r,int now,int L,int R,int v){
if((vor[now]&v)==vor[now])
return ;
if(L<=l&&r<=R&&(vor[now]&v)==(vand[now]&v)){
getlazy(now,vor[now]&v);
return ;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid)
updateand(l,mid,lc(now),L,R,v);
if(mid<R)
updateand(mid+1,r,rc(now),L,R,v);
pushup(now);
}
void updateor(int l,int r,int now,int L,int R,int v){
if((vand[now]|v)==vand[now])
return ;
if(L<=l&&r<=R&&(vand[now]|v)==(vor[now]|v)){
getlazy(now,vand[now]|v);
return ;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid)
updateor(l,mid,lc(now),L,R,v);
if(mid<R)
updateor(mid+1,r,rc(now),L,R,v);
pushup(now);
}
int query(int l,int r,int now,int L,int R){
if(L<=l&&r<=R)
return minn[now];
int mid=(l+r)>>1,res=inf;
pushdown(now);
if(L<=mid)
res=min(res,query(l,mid,lc(now),L,R));
if(mid<R)
res=min(res,query(mid+1,r,rc(now),L,R));
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
for(int i=1;i<=m;i++){
int opt,l,r,v;
scanf("%d%d%d",&opt,&l,&r);
if(opt==1){
scanf("%d",&v);
updateand(1,n,1,l,r,v);
}
if(opt==2){
scanf("%d",&v);
updateor(1,n,1,l,r,v);
}
if(opt==3)
printf("%d\n",query(1,n,1,l,r));
}
return 0;
}