FZU - 2105 Digits Count (线段树成段更新)

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2105点击打开链接

Problem 2105 Digits Count

Accept: 577    Submit: 2590
Time Limit: 10000 mSec    Memory Limit : 262144 KB

 Problem Description

Given N integers A={A[0],A[1],...,A[N-1]}. Here we have some operations:

Operation 1: AND opn L R

Here opn, L and R are integers.

For L≤i≤R, we do A[i]=A[i] AND opn (here "AND" is bitwise operation).

Operation 2: OR opn L R

Here opn, L and R are integers.

For L≤i≤R, we do A[i]=A[i] OR opn (here "OR" is bitwise operation).

Operation 3: XOR opn L R

Here opn, L and R are integers.

For L≤i≤R, we do A[i]=A[i] XOR opn (here "XOR" is bitwise operation).

Operation 4: SUM L R

We want to know the result of A[L]+A[L+1]+...+A[R].

Now can you solve this easy problem?

 Input

The first line of the input contains an integer T, indicating the number of test cases. (T≤100)

Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.

Then one line follows n integers A[0], A[1], ..., A[n-1] (0≤A[i]<16,0≤i<n).

Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)

 Output

For each test case and for each "SUM" operation, please output the result with a single line.

 Sample Input

14 41 2 4 7SUM 0 2XOR 5 0 0OR 6 0 3SUM 0 2

 Sample Output

718

 Hint

A = [1 2 4 7]

SUM 0 2, result=1+2+4=7;

XOR 5 0 0, A=[4 2 4 7];

OR 6 0 3, A=[6 6 6 7];

SUM 0 2, result=6+6+6=18.

 Source

“高教社杯”第三届福建省大学生程序设计竞赛

这道题很早之前就遇到了 但是因为当时oj卡住了一直没做

这道题第一眼看完的想法是造四个线段树记录区间里每个数的二进制的位数值

这个想法很棒啊。。

但是T了

看了题解才知道只需要正常的进行区间操作即可 因为数的范围很小必定存在大量重复的数

造四颗树==作死+弄巧成拙

当然网上有用进制实现的 目前太不想去思考自己的二进制版本哪里超时。。一来很久没打线段树 二来不喜欢做弄巧成拙的事

另外有一点比较疑惑

查询是如果将标记下放提前会T 而如果先查询后下放则不会。

有点玄学。。

 基础成段更新版:

#include <iostream>
#include <math.h>
using namespace std;
#define maxn 1000000
struct xjy
{
	int left;
	int right;
	int flag;
	int num;
}tree[maxn<<2];
int a[maxn+1];
int ans;
int tot;
void build(int root,int left,int right,int num)
{
	if(left==right)
	{
		tree[root].left=left;
		tree[root].right=right;
		tree[root].flag=1;
		tree[root].num=a[left-1];
		return;
	}
	tree[root].flag=0;
	tree[root].num=0;
	tree[root].left=left;
	tree[root].right=right;
	int mid=(left+right)>>1;
	build(root<<1,left,mid,num);
	build(root<<1|1,mid+1,right,num);
	if(tree[root<<1].flag&&tree[root<<1|1].flag&&tree[root<<1].num==tree[root<<1|1].num)
	{
		tree[root].flag=1;
		tree[root].num=tree[root<<1].num;
	}
	else 
		tree[root].flag=0;
}
void query(int root,int left,int right)
{
	
	if(left==tree[root].left&&right==tree[root].right&&tree[root].flag)
	{
		ans+=tree[root].num*(right-left+1);
		return;
	}
	if(tree[root].flag)
	{
		tree[root].flag=0;
		if(tree[root].left!=tree[root].right)
		{	
			tree[root<<1].flag=tree[root<<1|1].flag=1;
			tree[root<<1].num=tree[root<<1|1].num=tree[root].num;
		}
	}
	int mid=(tree[root].left+tree[root].right)>>1;
	if(mid>=right)
	{
		query(root<<1,left,right);
	}
	else if(mid<left)
	{
		query(root<<1|1,left,right);
	}
	else 
	{
		query(root<<1,left,mid);
		query(root<<1|1,mid+1,right);
	}	
	if(tree[root<<1].flag&&tree[root<<1|1].flag&&tree[root<<1].num==tree[root<<1|1].num)
	{
		tree[root].flag=1;
		tree[root].num=tree[root<<1].num;
	}
	else 
		tree[root].flag=0;
}
void update(int root,int left,int right,int val,int option)
{
	
	if(left==tree[root].left&&right==tree[root].right&&tree[root].flag)
	{
	
		if(option==1)
			tree[root].num&=val;
		else if(option==2)
			tree[root].num|=val;
		else 
			tree[root].num^=val;
		return;
	}
	if(tree[root].flag)
	{
		tree[root].flag=0;
		if(tree[root].left!=tree[root].right)
		{	
			tree[root<<1].flag=tree[root<<1|1].flag=1;
			tree[root<<1].num=tree[root<<1|1].num=tree[root].num;
		}
	}
	int mid=(tree[root].left+tree[root].right)>>1;
	if(mid>=right)
	{
		update(root<<1,left,right,val,option);
	}
	else if(mid<left)
	{
		update(root<<1|1,left,right,val,option);
	}
	else 
	{
		update(root<<1,left,mid,val,option);
		update(root<<1|1,mid+1,right,val,option);
	}	
	if(tree[root<<1].flag&&tree[root<<1|1].flag&&tree[root<<1].num==tree[root<<1|1].num)
	{
		tree[root].flag=1;
		tree[root].num=tree[root<<1].num;
	}
	else 
		tree[root].flag=0;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
		}
		for(int i=0;i<4;i++)
		{
			tot=0;
			build(1,1,n,i);
		}
		for(int i=0;i<m;i++)
		{
			char s[5];
			scanf(" %s",s);
			if(s[0]=='A')
			{
				int l,r,mid;
				scanf("%d%d%d",&mid,&l,&r);
				update(1,l+1,r+1,mid,1);
			}
			else if(s[0]=='O')
			{
				int l,r,mid;
				scanf("%d%d%d",&mid,&l,&r);
				update(1,l+1,r+1,mid,2);
			}
			else if(s[0]=='X')
			{
				int l,r,mid;
				scanf("%d%d%d",&mid,&l,&r);
				update(1,l+1,r+1,mid,3);
			}
			else 
			{
				int l,r;
				scanf("%d%d",&l,&r);
				ans=0; 
				query(1,l+1,r+1);
				printf("%d\n",ans);
			}
		}
	}
	
}

作死二进制之TLE版:

#include <iostream>
#include <math.h>
using namespace std;
#define maxn 800000
struct xjy
{
	int left;
	int right;
	int flag;
	int num;
}tree[4][maxn<<2];
int a[4][maxn+1];
int ans;
int tot;
void build(int root,int left,int right,int num)
{
	if(left==right)
	{
		tree[num][root].left=left;
		tree[num][root].right=right;
		tree[num][root].flag=1;
		tree[num][root].num=a[num][left-1];
		return;
	}
	tree[num][root].flag=0;
	tree[num][root].num=0;
	tree[num][root].left=left;
	tree[num][root].right=right;
	int mid=(left+right)>>1;
	build(root<<1,left,mid,num);
	build(root<<1|1,mid+1,right,num);
	if(tree[num][root<<1].flag&&tree[num][root<<1|1].flag&&tree[num][root<<1].num==tree[num][root<<1|1].num)
	{
		tree[num][root].flag=1;
		tree[num][root].num=tree[num][root<<1].num;
	}
	else 
		tree[num][root].flag=0;
}
void query(int root,int left,int right,int num)
{
	
	if(left==tree[num][root].left&&right==tree[num][root].right&&tree[num][root].flag)
	{
		
		ans+=pow(2,num)*tree[num][root].num*(right-left+1);
		return;
	}
	if(tree[num][root].flag)
	{
		tree[num][root].flag=0;
		if(tree[num][root].left!=tree[num][root].right)
		{	
			tree[num][root<<1].flag=tree[num][root<<1|1].flag=1;
			tree[num][root<<1].num=tree[num][root<<1|1].num=tree[num][root].num;
		}
	}
	int mid=(tree[num][root].left+tree[num][root].right)>>1;
	if(mid>=right)
	{
		query(root<<1,left,right,num);
	}
	else if(mid<left)
	{
		query(root<<1|1,left,right,num);
	}
	else 
	{
		query(root<<1,left,mid,num);
		query(root<<1|1,mid+1,right,num);
	}	
	if(tree[num][root<<1].flag&&tree[num][root<<1|1].flag&&tree[num][root<<1].num==tree[num][root<<1|1].num)
	{
		tree[num][root].flag=1;
		tree[num][root].num=tree[num][root<<1].num;
	}
	else 
		tree[num][root].flag=0;
}
void update(int root,int left,int right,int num,int val,int option)
{
	
	if(left==tree[num][root].left&&right==tree[num][root].right&&tree[num][root].flag)
	{
		
		if(option==1)
			tree[num][root].num&=val;
		else if(option==2)
			tree[num][root].num|=val;
		else 
			tree[num][root].num^=val;
		return;
	}
	if(tree[num][root].flag)
	{
		tree[num][root].flag=0;
		if(tree[num][root].left!=tree[num][root].right)
		{	
			tree[num][root<<1].flag=tree[num][root<<1|1].flag=1;
			tree[num][root<<1].num=tree[num][root<<1|1].num=tree[num][root].num;
		}
	}
	int mid=(tree[num][root].left+tree[num][root].right)>>1;
	if(mid>=right)
	{
		update(root<<1,left,right,num,val,option);
	}
	else if(mid<left)
	{
		update(root<<1|1,left,right,num,val,option);
	}
	else 
	{
		update(root<<1,left,mid,num,val,option);
		update(root<<1|1,mid+1,right,num,val,option);
	}	
	if(tree[num][root<<1].flag&&tree[num][root<<1|1].flag&&tree[num][root<<1].num==tree[num][root<<1|1].num)
	{
		tree[num][root].flag=1;
		tree[num][root].num=tree[num][root<<1].num;
	}
	else 
		tree[num][root].flag=0;
}
void show(int root ,int num)
{
	if(tree[num][root].left==tree[num][root].right)
	{
		cout << tree[num][root].left << tree[num][root].right << tree[num][root].flag << tree[num][root].num << endl;
		return;
	}
	cout << tree[num][root].left << tree[num][root].right << tree[num][root].flag << tree[num][root].num << endl;
	show(root<<1,num);
	show(root<<1|1,num);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		for(int i=0;i<4;i++)
			for(int j=0;j<maxn;j++)
			{
				a[i][j]=0;
			}
		for(int i=0;i<4;i++)
			for(int j=0;j<(maxn>>2);j++)
			{
				tree[i][j].left=tree[i][j].right=tree[i][j].flag=tree[i][j].num=0;
			}
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++)
		{
			int mid;
			cin >> mid;
			for(int j=3;j>=0;j--)
			{
				if(mid>=pow(2,j))
				{
					a[j][i]=1;
					mid-=pow(2,j);
				}
				else 
					a[j][i]=0;
			}
		}
		for(int i=0;i<4;i++)
		{
			tot=0;
			build(1,1,n,i);
		}
		//for(int i=0;i<4;i++)
		{
			//show(1,i);
			//cout << endl;
		}
		for(int i=0;i<m;i++)
		{
			string s;
			cin >> s;
			if(s[0]=='A')
			{
				int l,r,mid;
				scanf("%d%d%d",&mid,&l,&r);
				for(int j=3;j>=0;j--)
				{
					if(mid>=pow(2,j))
					{
						update(1,l+1,r+1,j,1,1);
						mid-=pow(2,j);
					}
					else 
						update(1,l+1,r+1,j,0,1);
				}
			}
			else if(s[0]=='O')
			{
				int l,r,mid;
				scanf("%d%d%d",&mid,&l,&r);
				for(int j=3;j>=0;j--)
				{
					if(mid>=pow(2,j))
					{
						update(1,l+1,r+1,j,1,2);
						mid-=pow(2,j);
					}
					else 
						update(1,l+1,r+1,j,0,2);
				}
			}
			else if(s[0]=='X')
			{
				int l,r,mid;
				scanf("%d%d%d",&mid,&l,&r);
				for(int j=3;j>=0;j--)
				{
					if(mid>=pow(2,j))
					{
						update(1,l+1,r+1,j,1,3);
						mid-=pow(2,j);
					}
					else 
						update(1,l+1,r+1,j,0,3);
				}
			}
			else 
			{
				int l,r;
				scanf("%d%d",&l,&r);
				ans=0; 
				for(int j=0;j<4;j++)
					query(1,l+1,r+1,3-j);
				printf("%d\n",ans);
			}
		}
	}
	
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值