拆位线段树(&,|,移位)

位运算?位运算!

由于是循环移位,所以不用担心越界的情况

在&,|的时候考虑一下相关的性质:

&:该位为1,则没有影响,为0,就全部置0

|:和&刚好相反

#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define inf 0x7fffffff
//#define ll long long
#define int long long
//#define double long double
#define re int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
const int mod=1e9+7;
const int M=1e8+5;
const int N=8e5+5;//?????????? 4e8
struct nod
{
	int sum[25],add;
}e[N];
int n,m;
int b[N];
void push(int p)
{
	for(re i=0;i<20;i++)   e[p].sum[i]=e[ls(p)].sum[i]+e[rs(p)].sum[i];
}
void bulid(int p,int l,int r)
{
	if(l==r)
	{
		int x;
		scanf("%lld",&x);
		for(re i=0;i<20;i++)  if((1<<i)&x)  e[p].sum[i]=1;
		return;
	}
	int mid=(l+r)>>1;
	bulid(ls(p),l,mid);bulid(rs(p),mid+1,r);
	push(p);
}
void rotate(int p,int len)
{
	for(re i=0;i<20;i++)  b[i]=e[p].sum[(i+len)%20];
	for(re i=0;i<20;i++)  e[p].sum[i]=b[i];
	e[p].add+=len;
	e[p].add%=20;
}
void spread(int p,int l,int r)
{
	if(e[p].add)
	{
		rotate(ls(p),e[p].add);
		rotate(rs(p),e[p].add);
		e[p].add=0;
	}
	int mid=(l+r)>>1;
	for(re i=0;i<20;i++)
	{
		if(e[p].sum[i]==0)  e[ls(p)].sum[i]=e[rs(p)].sum[i]=0;
		else if(e[p].sum[i]==r-l+1)  {e[ls(p)].sum[i]=mid-l+1,e[rs(p)].sum[i]=r-mid;}
	}
}
void update(int p,int L,int R,int l,int r,int v,int op)
{
	if(L<=l&&r<=R)
	{
		if(op==1)  rotate(p,v);
		else if(op==2)  rotate(p,20-v);
		else if(op==3)
		{
			for(re i=0;i<20;i++)  if(((v>>i)&1))  e[p].sum[i]=r-l+1;
		}
		else
		{
			for(re i=0;i<20;i++)  if(!((v>>i)&1))  e[p].sum[i]=0;
		}
		return;
	}
	spread(p,l,r);
	int mid=(l+r)>>1;
	if(L<=mid)  update(ls(p),L,R,l,mid,v,op);
	if(mid<R)  update(rs(p),L,R,mid+1,r,v,op);
	push(p);
}
int ask(int p,int id,int L,int R,int l,int r)
{
	if(L<=l&&r<=R)  return e[p].sum[id];
	spread(p,l,r);
	int mid=(l+r)>>1;
	int ans=0;
	if(L<=mid)  ans+=ask(ls(p),id,L,R,l,mid);
	if(mid<R)  ans+=ask(rs(p),id,L,R,mid+1,r);
	return ans;
}
void solve()
{
	cin>>n>>m;
	bulid(1,1,n);
	while(m--)
	{
		int op,l,r,x;
		scanf("%lld%lld%lld%lld",&op,&l,&r,&x);
		if(op<5)   update(1,l,r,1,n,x,op);
		else
		{
			int ans=0;
			for(re i=0;i<20;i++)  ans+=(ask(1,i,l,r,1,n)*(1<<i));
			printf("%lld\n",ans);
		}
	}
}
signed main()
{
    int T=1;
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
//    	printf("Case %d:\n",index);
        solve();
//        puts("");
    }
    return 0;
}
/*


1
6 5
0 0 0 122 499 8888




*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值