fzu-2105(线段树区间更新)

27 篇文章 0 订阅
15 篇文章 0 订阅

题意:区间有三种二进制操作,区间中的值不超过16,然后查询区间和。因为每个数很小,所以区间内存在大量重复值,并且经过二进制操作后区间中相等的值会越来越多。我们只需要记录当前区间中的值是否相等即可。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int tree[1000000*4];
int a[1000000];
void push_down(int l,int r,int k)
{
	if(tree[k<<1]!=-1&&tree[k<<1|1]==tree[k<<1])
	{
		tree[k]=tree[k<<1];
	}
}
void build(int l,int r,int k)
{
	tree[k]=-1;
	if(l==r)
	{
		tree[k]=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,k<<1);
	build(mid+1,r,k<<1|1);
	push_down(l,r,k);
}
void update(int L,int R,int l,int r,int k,int flag,int val)
{
	int mid=(L+R)>>1;
	if(L>=l&&R<=r&&tree[k]!=-1)
	{
		if(flag==1)tree[k]^=val;
		else if(flag==2)tree[k]|=val;
		else if(flag==3)tree[k]&=val;
		return ;
	}
	if(tree[k]>=0)		//下传标记 
	{
		tree[k<<1]=tree[k<<1|1]=tree[k];tree[k]=-1;
	}
	if(l<=mid) update(L,mid,l,r,k<<1,flag,val);
	if(r>mid) update(mid+1,R,l,r,k<<1|1,flag,val);
	push_down(L,R,k);//上传标记 
}
int query(int L,int R,int l,int r,int k)
{
	int ans=0;
	int mid=(L+R)>>1;
	if(L>=l&&R<=r&&tree[k]!=-1)
	{
		return tree[k]*(R-L+1);
	}
	if(tree[k]>=0)		//下传标记 
	{
		tree[k<<1]=tree[k<<1|1]=tree[k];tree[k]=-1;
	}
	if(l<=mid)
	ans+=query(L,mid,l,r,k<<1);
	if(r>mid)
	ans+=query(mid+1,R,l,r,k<<1|1);
	push_down(L,R,k);//上传标记
	return ans;
}
int main()
{
	int t;scanf("%d",&t);
	while(t--)
	{
		int n,q;
		scanf("%d%d",&n,&q);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		build(1,n,1);
		while(q--)
		{
			char s[5];int x,y,z;
			scanf("%s",s);
			if(s[0]=='S')
			{
				scanf("%d%d",&x,&y);x++;y++;
				printf("%d\n",query(1,n,x,y,1));
			}
			else if(s[0]=='X')
			{
				scanf("%d%d%d",&z,&x,&y);x++;y++;
				update(1,n,x,y,1,1,z);		//orx
			}
			else if(s[0]=='O')
			{
				scanf("%d%d%d",&z,&x,&y);x++;y++;
				update(1,n,x,y,1,2,z);		//or
			}
			else
			{
				scanf("%d%d%d",&z,&x,&y);x++;y++;			//and
				update(1,n,x,y,1,3,z);
			}
		}
	}
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值