LOJ#6507. 「雅礼集训 2018 Day7」A 题解
直接线段树上打\(tag\)即可,如果遇到打tag之后存在不同的值的区间,那么就往下递归。
复杂度分析 :
记一个节点的势能 \(f(node) = \sum\limits_{i=0}^{31} g(node,i),\)其中 \(g(node,i)\) 表示 \(node\) 节点内部的所有数字中,第 \(i\) 个二进制位上是(1)/否(0)有不同的值。
一开始势能是 \(O(n\log n \times 31)\) 的。
每次修改最多增加\(O(\log n \times 31)\) 的势能,过程中如果暴力递归了一次那么势能必然也会减去1,所以复杂度为\(O((n+m) \log n \times 31).\)
code :
#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &x){
static char ch; x = 0,ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
inline void write(int x){ if (x > 9) write(x/10); putchar(x%10+'0'); }
const int N = 524288 + 1,ALL = (1ll<<31)-1;
int n,a[N];
struct Node{
int mn,v0,v1;
}t[N<<2];
#define lc o<<1
#define rc o<<1|1
inline void up(int o){
t[o].v1 = t[lc].v1 & t[rc].v1,t[o].v0 = t[lc].v0 & t[rc].v0,t[o].mn = min(t[lc].mn,t[rc].mn);
}
inline void Build(int o,int l,int r){
if (l == r){ t[o].mn = t[o].v1 = a[l],t[o].v0 = ALL^a[l]; return; }
int mid = l+r>>1; Build(lc,l,mid); Build(rc,mid+1,r); up(o);
}
inline void down(int o){
if ((t[o].v0 | t[o].v1) == ALL) t[lc] = t[rc] = t[o];
}
int ll,rr;
inline void Or(int o,int l,int r,int v){
v &= ALL ^ t[o].v1; if (!v) return;
if (ll <= l && rr >= r){
if ((v | t[o].v1 | t[o].v0) == ALL){
t[o].v1 |= v,t[o].v0 = ALL ^ t[o].v1,t[o].mn = t[o].v1; return;
}
down(o); int mid = l+r>>1; Or(lc,l,mid,v); Or(rc,mid+1,r,v); up(o); return;
}
down(o); int mid = l+r>>1;
if (ll <= mid) Or(lc,l,mid,v); if (rr > mid) Or(rc,mid+1,r,v); up(o);
}
inline void And(int o,int l,int r,int v){
v &= ALL ^ t[o].v0; if (!v) return;
if (ll <= l && rr >= r){
if ((v | t[o].v1 | t[o].v0) == ALL){
t[o].v0 |= v,t[o].v1 = ALL ^ t[o].v0,t[o].mn = t[o].v1; return;
}
down(o); int mid = l+r>>1; And(lc,l,mid,v); And(rc,mid+1,r,v); up(o); return;
}
down(o); int mid = l+r>>1;
if (ll <= mid) And(lc,l,mid,v); if (rr > mid) And(rc,mid+1,r,v); up(o);
}
int qans;
inline void Ask(int o,int l,int r){
if (ll <= l && rr >= r || ALL == (t[o].v0 | t[o].v1)){ qans = min(qans,t[o].mn); return; }
int mid = l+r>>1; if (ll <= mid) Ask(lc,l,mid); if (rr > mid) Ask(rc,mid+1,r);
}
#undef lc
#undef rc
int main(){
int i,m,op,x;
read(n),read(m); for (i = 1; i <= n; ++i) read(a[i]); Build(1,1,n);
while (m--){
read(op),read(ll),read(rr); if (op <= 2) read(x);
if (op == 1) And(1,1,n,ALL^x);
if (op == 2) Or(1,1,n,x);
if (op == 3) qans = ALL,Ask(1,1,n),write(qans),putchar('\n');
}
return 0;
}