Description
给出一个长度为n的序列a,要求资瓷
区间或,区间与和求区间最小值
n<=5e5,ai<2^31
Solution
让我们先来考虑一个暴力:
如果一次操作对某个区间的影响是一样的(即最小值还是那个数),那么我们直接打标记退出;若一次操作对某个区间无影响就直接退出
只需要维护区间or和区间and
然后你就会发现你过了_ (:з」∠) _
这是为什么呢?
让我们来分析一波复杂度:
设势函数
ϕ
(
s
)
=
f
(
s
)
+
ϕ
(
l
e
f
t
(
s
)
)
+
ϕ
(
r
i
g
h
t
(
s
)
)
\phi(s)=f(s)+\phi(left(s))+\phi(right(s))
ϕ(s)=f(s)+ϕ(left(s))+ϕ(right(s))
令
k
=
log
2
(
m
a
x
(
a
i
)
)
k=\log_2(max(ai))
k=log2(max(ai)),
f
(
s
)
=
∑
i
=
0
k
g
(
s
,
i
)
f(s)=\sum_{i=0}^{k}g(s,i)
f(s)=∑i=0kg(s,i)
其中若区间s中所有数的二进制的第i为都相同,则g(s,i)=0,否则g(s,i)=1
那么初始情况下
ϕ
(
r
o
o
t
)
=
O
(
n
k
log
n
)
\phi(root)=O(nk\log n)
ϕ(root)=O(nklogn)
考虑
ϕ
(
r
o
o
t
)
\phi(root)
ϕ(root)的变化:
当我们下传标记时,
ϕ
(
r
o
o
t
)
\phi(root)
ϕ(root)的变化量为O(k)
当我们新增标记时,
ϕ
(
r
o
o
t
)
\phi(root)
ϕ(root)的变化量为O(k log k)
当我们访问一个节点时,必然会使这个点的f(s)-1
所以总复杂度O(nklog n)
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
void write(int x) {
if (!x) {puts("0");return;}
char ch[20];int tot=0;
for(;x;x/=10) ch[++tot]=x%10+'0';
fd(i,tot,1) putchar(ch[i]);
puts("");
}
const int N=5e5+5,Mx=0x7fffffff;
int n,m,_or[N<<2],_and[N<<2],a[N];
struct Segment_Tree{
int _or,_and,mn;
friend Segment_Tree operator + (Segment_Tree a,Segment_Tree b) {
Segment_Tree c;
c._or=a._or|b._or;
c._and=a._and&b._and;
c.mn=min(a.mn,b.mn);
return c;
}
}tr[N<<2];
void build(int v,int l,int r) {
_or[v]=0;_and[v]=Mx;
if (l==r) {
tr[v]._or=tr[v]._and=tr[v].mn=a[l];
return;
}
int mid=l+r>>1;
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
tr[v]=tr[v<<1]+tr[v<<1|1];
}
void Or(int v,int z) {
tr[v]._or|=z;tr[v]._and|=z;tr[v].mn|=z;
_or[v]|=z;_and[v]|=z;
}
void And(int v,int z) {
tr[v]._or&=z;tr[v]._and&=z;tr[v].mn&=z;
_or[v]&=z;_and[v]&=z;
}
void down(int v) {
if (_or[v]) {
Or(v<<1,_or[v]);
Or(v<<1|1,_or[v]);
_or[v]=0;
}
if (_and[v]!=Mx) {
And(v<<1,_and[v]);
And(v<<1|1,_and[v]);
_and[v]=Mx;
}
}
void modify_and(int v,int l,int r,int x,int y,int z) {
if ((tr[v]._or&z)==tr[v]._or) return;
if (x<=l&&r<=y&&(tr[v]._and&z)==(tr[v]._or&z)) {
And(v,z);
return;
}
int mid=l+r>>1;down(v);
if (x<=mid) modify_and(v<<1,l,mid,x,y,z);
if (y>mid) modify_and(v<<1|1,mid+1,r,x,y,z);
tr[v]=tr[v<<1]+tr[v<<1|1];
}
void modify_or(int v,int l,int r,int x,int y,int z) {
if ((tr[v]._and|z)==tr[v]._and) return;
if (x<=l&&r<=y&&(tr[v]._and|z)==(tr[v]._or|z)) {
Or(v,z);
return;
}
int mid=l+r>>1;down(v);
if (x<=mid) modify_or(v<<1,l,mid,x,y,z);
if (y>mid) modify_or(v<<1|1,mid+1,r,x,y,z);
tr[v]=tr[v<<1]+tr[v<<1|1];
}
int query(int v,int l,int r,int x,int y) {
if (x<=l&&r<=y) return tr[v].mn;
int mid=l+r>>1,mn=Mx;down(v);
if (x<=mid) mn=min(mn,query(v<<1,l,mid,x,y));
if (y>mid) mn=min(mn,query(v<<1|1,mid+1,r,x,y));
return mn;
}
int main() {
n=read();m=read();
fo(i,1,n) a[i]=read();
build(1,1,n);
for(;m;m--) {
int opt=read(),l=read(),r=read();
if (opt==1) {
int k=read();
modify_and(1,1,n,l,r,k);
}
if (opt==2) {
int k=read();
modify_or(1,1,n,l,r,k);
}
if (opt==3) write(query(1,1,n,l,r));
}
return 0;
}