和Leo一起做热爱线段树的好孩子FZU2105

经典题

由于异或等操作是不满足结合律的

所以按二进制位拆分

建四棵线段树就转化为区间取反和区间set

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline void read(int &x){
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
#define lc (p<<1)
#define rc (p<<1|1)
const int N=1e6+100;
int val[N];
struct Segment_Tree{
	struct Node{
		int lazy,len;
		int sum;
	}T[4][N<<2];
	void Clear(){
		memset(T,0,sizeof(T));
	}
	inline void PushUp(int p,int Id){
		T[Id][p].len=T[Id][lc].len+T[Id][rc].len;
		T[Id][p].sum=T[Id][lc].sum+T[Id][rc].sum;
	}
	inline void PushDown(int p,int Id){		
		int flag=0;
		if(T[Id][p].sum==T[Id][p].len){
			flag=1;
			T[Id][lc].sum=T[Id][lc].len;
			T[Id][rc].sum=T[Id][rc].len;
		}
		else{
			if(T[Id][p].sum==0){
				flag=1;
				T[Id][lc].sum=T[Id][rc].sum=0;
			}
		}
		if(T[Id][p].lazy){
			T[Id][lc].lazy^=1;
			T[Id][rc].lazy^=1;
			if(!flag){
				T[Id][lc].sum=T[Id][lc].len-T[Id][lc].sum;
				T[Id][rc].sum=T[Id][rc].len-T[Id][rc].sum;				
			}
			T[Id][p].lazy=0;
		}

	}
	inline void build(int p,int l,int r,int Id){
		T[Id][p].lazy=0;
		if(l==r){
			if(val[l]&(1<<Id)){
				T[Id][p].sum=1;
			}
			else T[Id][p].sum=0;
			T[Id][p].len=1;
			return;
		} 
		int mid=(l+r)/2;
		build(lc,l,mid,Id);
		build(rc,mid+1,r,Id);
		PushUp(p,Id);
	}
	inline void Update_And(int p,int Dl,int Dr,int l,int r,int Id){//set 0
		if(l<=Dl&&Dr<=r){
			T[Id][p].sum=0;
			T[Id][p].lazy=0;
			return;
		}
		PushDown(p,Id);
		int mid=(Dl+Dr)/2;
		if(l<=mid)Update_And(lc,Dl,mid,l,r,Id);
		if(mid< r)Update_And(rc,mid+1,Dr,l,r,Id);
		PushUp(p,Id);
	}
	inline void Update_Or (int p,int Dl,int Dr,int l,int r,int Id){
		if(l<=Dl&&Dr<=r){
			T[Id][p].sum=T[Id][p].len;
			T[Id][p].lazy=0;
			return;
		}
		PushDown(p,Id);
		int mid=(Dl+Dr)/2;
		if(l<=mid)Update_Or(lc,Dl,mid,l,r,Id);
		if(mid< r)Update_Or(rc,mid+1,Dr,l,r,Id);
		PushUp(p,Id);
	}
	inline void Update_Xor(int p,int Dl,int Dr,int l,int r,int Id){
		if(l<=Dl&&Dr<=r){
			T[Id][p].sum=T[Id][p].len-T[Id][p].sum;
			T[Id][p].lazy^=1;
			return;
		}
		PushDown(p,Id);
		int mid=(Dl+Dr)/2;
		if(l<=mid)Update_Xor(lc,Dl,mid,l,r,Id);
		if(mid< r)Update_Xor(rc,mid+1,Dr,l,r,Id);
		PushUp(p,Id);
	}
	inline int Query(int p,int Dl,int Dr,int l,int r,int Id){
		if(l<=Dl&&Dr<=r){
			return T[Id][p].sum;
		}
		PushDown(p,Id);
		int ans=0;
		int mid=(Dl+Dr)/2;
		if(l<=mid)ans+=Query(lc,Dl,mid,l,r,Id);
		if(mid< r)ans+=Query(rc,mid+1,Dr,l,r,Id);
		return ans;
	}
}Tree;
int n,m;
int main(){
//	freopen("FZU2105.in","r",stdin);
	int Cas;
	read(Cas);
	while(Cas--){
		Tree.Clear();
		read(n);
		read(m);
		for(int i=1;i<=n;i++){
			read(val[i]);
		}
		for(int i=0;i<4;i++)
		Tree.build(1,1,n,i);
		for(int i=1;i<=m;i++){
			char opt[10];
			scanf("%s",opt);
			if(opt[0]=='S'){
				int l,r;
				read(l);
				read(r);
				l++;
				r++;
				int ans=0;
				for(int i=0;i<4;i++){
					int now=Tree.Query(1,1,n,l,r,i);
					ans+=now*(1<<i);
				}
				cout<<ans<<'\n';
			}
			if(opt[0]=='X'){
				int x,l,r;
				read(x);
				read(l);
				read(r);
				l++;
				r++;
				for(int i=0;i<4;i++){
					if((1<<i)&x)Tree.Update_Xor(1,1,n,l,r,i);//,cout<<i<<" id "<<'\n';
				}
			}
			if(opt[0]=='A'){
				int x,l,r;
				read(x);
				read(l);
				read(r);
				l++;
				r++;
				for(int i=0;i<4;i++){
					if(!((1<<i)&x))
					Tree.Update_And(1,1,n,l,r,i);
				}
			}
			if(opt[0]=='O'){
				int x,l,r;
				read(x);
				read(l);
				read(r);
				l++;
				r++;
				for(int i=0;i<4;i++){
					if((1<<i)&x)
					Tree.Update_Or(1,1,n,l,r,i);
				}
			}
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值