COGS 2638. 數列操作ψ 線段樹
阿新 • • 發佈:2018-06-15
司機 同時 PE clu 很多 true con 數列 們的
傳送門 : COGS 2638. 數列操作ψ 線段樹
這道題讓我們維護區間最大值,以及維護區間and,or一個數
我們考慮用線段樹進行維護,這時候我們就要用到吉司機線段樹啦 QAQ
由於發現若幹次and,or之後,如果數據分布均勻,那麽幾乎所有的數在若幹次操作後都會變成同一個數
因為我們的and操作中的0位,以及or操作當中的1位,都是可以把整個區間的那一二進制位重置為相同的
我們考慮利用這一個性質
如果我們直接維護一個區間內的值是否是相同的,那麽效果會差很多。
我們發現我們在進行and操作的時候只有為0的二進制位才可能更改原本的二進制位
同樣的,在進行or操作的時候也只有為1的二進制位才可能更改原本的二進制位
所以我們可以在區間內所有的數的對應的會做出修改的二進制位完全相同時作出區間整體修改
至於區間整體修改,我們很容易發現,實際上就是區間內加上一個數
所以對於每一個線段樹節點,維護一個sam值,表示這個線段樹代表的區間內二進制位的相同情況
對應二進制位為1,則代表區間內所有值的這一位都是相同的
隨後我們通過對區間內所有元素對應二進制位是否相同的情況來判斷是否可以進行區間修改即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline void read(int &x){
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);++i)
const int maxn = 100010;
const int bas = 0x7fffffff;
int T[maxn<<2],lazy[maxn<<2],sam[maxn<<2];
int a[maxn];
inline void update(int rt){
T[rt] = max(T[rt<<1],T[rt<<1|1]);
sam[rt] = (sam[rt<<1]&sam[rt<<1|1]) & (~(T[rt<<1]^T[rt<<1|1]));
}
inline void pushdown(int rt){
if(lazy[rt] == 0) return ;
T[rt<<1] += lazy[rt];lazy[rt<<1] += lazy[rt];
T[rt<<1|1] += lazy[rt];lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
void build(int rt,int l,int r){
if(l == r){
T[rt] = a[l];
sam[rt] = bas;
return ;
}int mid = l+r >> 1;
build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
update(rt);
}
int L,R,val,tmp;
inline bool check_a(int rt){
tmp = (val^bas);
return (tmp & sam[rt]) == tmp;
}
void modify_a(int rt,int l,int r){
if(L <= l && r <= R && check_a(rt)){
tmp = (T[rt] & val) - T[rt];
lazy[rt] += tmp;T[rt] += tmp;
return ;
}int mid = l+r >> 1;pushdown(rt);
if(L <= mid) modify_a(rt<<1,l,mid);
if(R > mid) modify_a(rt<<1|1,mid+1,r);
update(rt);
}
void modify_o(int rt,int l,int r){
if(L <= l && r <= R && (sam[rt] & val) == val){
tmp = (T[rt] | val) - T[rt];
lazy[rt] += tmp;T[rt] += tmp;
return ;
}int mid = l+r >> 1;pushdown(rt);
if(L <= mid) modify_o(rt<<1,l,mid);
if(R > mid) modify_o(rt<<1|1,mid+1,r);
update(rt);
}
int query(int rt,int l,int r){
if(L <= l && r <= R) return T[rt];
int mid = l+r >> 1;pushdown(rt);
if(R <= mid) return query(rt<<1,l,mid);
if(L > mid) return query(rt<<1|1,mid+1,r);
return max(query(rt<<1,l,mid),query(rt<<1|1,mid+1,r));
}
int main(){
//freopen("series_wei.in","r",stdin);
//freopen("series_wei.out","w",stdout);
int n,m;read(n);read(m);
rep(i,1,n) read(a[i]);
build(1,1,n);int opt;
int cnt = 0 ;
while(m--){
read(opt);read(L);read(R);
if(opt == 1) read(val),modify_a(1,1,n);
else if(opt == 2) read(val),modify_o(1,1,n);
else printf("%d\n",query(1,1,n));
}
return 0;
}
COGS 2638. 數列操作ψ 線段樹