COGS 2638. 数列操作ψ 线段树
Posted skyminer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了COGS 2638. 数列操作ψ 线段树相关的知识,希望对你有一定的参考价值。
传送门 : 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
",query(1,1,n));
}
return 0;
}
以上是关于COGS 2638. 数列操作ψ 线段树的主要内容,如果未能解决你的问题,请参考以下文章
cogs 1963. [HAOI 2015] 树上操作 树链剖分+线段树