COGS-2638 区间与,异或,询问max
本篇题解参考了这个博客
我们利用线段树来维护区间第最大值,考虑如何修改
每一次进行与操作时只有z的二进制为0的位会产生影响
每一次进行或操作时只有z的二进制为1的位会产生影响
所以只要该区间二进制相同的位刚好是z会产生影响的二进制为位
那么该修改对这个区间的影响是一样的,我们就可以用一个区间修改的标记进行维护
标记下传也很简单
现在的问题是如何快速合并两个区间
我们用0表示该区间第k位二进制位不同,1表示相同
显然可以用一个int来存下
左右区间相同的二进制位一定是左边区间相同的和右边区间相同的二进制位的交集的子集
显然 same[l]&same[r]就是交集 但是我们还要判断第k位在左右区间究竟是否相同
有可能左边第k位都是0,右边第k位全是1
我们只要左右区间各取一个代表元素,然后将这两个代表元素的相同位取出来与一下(same[l] & same[r])就好了
复杂度度大概是nlogn
# include<cstdio> # include<algorithm> # include<cstdlib> # include<ctime> # include<iostream> using namespace std; const int mn = 100005; int a[mn]; struct segment{ int mx[mn*4],sam[mn*4],tag[mn*4]; int bas; void updown(int cur) { mx[cur]=max(mx[cur<<1],mx[cur<<1|1]); sam[cur]=((sam[cur<<1] & sam[cur<<1|1]) & (~(mx[cur<<1] ^ mx[cur<<1|1]))); } void pushdown(int cur) { if(tag[cur]) { mx[cur<<1]+=tag[cur]; mx[cur<<1|1]+=tag[cur]; tag[cur<<1]+=tag[cur]; tag[cur<<1|1]+=tag[cur]; tag[cur]=0; } } void build(int l,int r,int cur) { if(l==r) { mx[cur]=a[l]; sam[cur]=bas; return ; } int mid=l+r>>1; build(l,mid,cur<<1); build(mid+1,r,cur<<1|1); updown(cur); } bool check(int cur,int val) { int tmp=(val ^ bas); return (tmp & sam[cur])==tmp; } void update1(int l,int r,int cur,int L,int R,int z) { if(l>R || r<L) return ; if(l>=L && r<=R && check(cur,z)) { int tmp = (mx[cur] & z) - mx[cur]; tag[cur]+=tmp; mx[cur]+=tmp; return ; } int mid=l+r>>1; pushdown(cur); update1(l,mid,cur<<1,L,R,z); update1(mid+1,r,cur<<1|1,L,R,z); updown(cur); } void update2(int l,int r,int cur,int L,int R,int z) { if(l>R || r<L) return ; if(l>=L && r<=R && ((z& sam[cur]) ==z)) { int tmp = (mx[cur] | z) - mx[cur]; tag[cur]+=tmp; mx[cur] +=tmp; return ; } int mid=l+r>>1; pushdown(cur); update2(l,mid,cur<<1,L,R,z); update2(mid+1,r,cur<<1|1,L,R,z); updown(cur); } int query(int l,int r,int cur,int L,int R) { if(l>=L && r<=R) return mx[cur]; if(l>R || r<L) return 0; int mid=l+r>>1; pushdown(cur); int ret=0; ret=max(query(l,mid,cur<<1,L,R),query(mid+1,r,cur<<1|1,L,R)); updown(cur); return ret; } }T; int n,m; int main() { int opt,x,y,z; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); T.bas=2147483647; T.build(1,n,1); for(int i=1;i<=m;i++) { scanf("%d%d%d",&opt,&x,&y); if(opt==1) { scanf("%d",&z); T.update1(1,n,1,x,y,z); } else if(opt==2) { scanf("%d",&z); T.update2(1,n,1,x,y,z); } else printf("%d\n",T.query(1,n,1,x,y)); } return 0; }