【或位运算】【构造】

题面

算法

关于这种有关二进制位的运算
我们照例是对每一位进行考虑
我们先把要构造的数列 (a_1,a_2,a_3······a_n)的二进制下的每一位初始值设为1
然后对于一条指令 l,r,p 如果二进制下p的第x位为0 则把l~r的数这一位都设为0 这一步可以用差分来(O(n))实现
我们已经对于每一条指令的0更新完毕
接下来考虑如果二进制下p的第x位为1,则l~r的数这一位的和不为0,如果不满足则证明无解
然后按照我们给的二进制下每个数的每一位还原原数组即可

代码

#include<iostream>
#include<cstdio>
#define M 100050
#define ll long long
using namespace std;
ll biao[40][M],num[M];//第一维:二进制第几位 第二维:第几个数
ll n,m,s[40][M];//s:前缀和 判断1的时候用 
struct QWQ{
	ll l,r,p;
}QAQ[M];//条件 
void change(ll num)
{
     for(ll i = 0;i <= 30;i++)
     if((QAQ[num].p&(1 << i)) == 0)
	 biao[i][QAQ[num].l] --,biao[i][QAQ[num].r + 1] ++;
	 return ;    
}
bool  check(ll num)
{
	for(ll i = 0;i <= 30;i++)
	{
		if(QAQ[num].p&(1 << i))
		if(s[i][QAQ[num].r] - s[i][QAQ[num].l - 1] == 0)
		return 1;
	}
	return 0;
}
int main()
{
	freopen("or.in","r",stdin);
	freopen("or.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(ll i = 1;i <= m;i++)
    {
    	scanf("%lld%lld%lld",&QAQ[i].l,&QAQ[i].r,&QAQ[i].p);
	    change(i); 
	} 
	for(ll i = 0;i <= 30;i++)
	for(ll j = 1;j <= n;j++)
	{
		biao[i][j] += biao[i][j - 1];
		if(biao[i][j] >= 0)
		num[j] |= (1 << i),s[i][j] = 1;
		s[i][j] += s[i][j - 1];
	} 
	for(ll i = 1;i <= m;i++)
    if(check(i))
	{
		cout<<"No"<<endl;
		return 0;
	}	
	cout<<"Yes"<<endl;
	for(ll i = 1;i <= n;i++)
	cout<<num[i]<<" ";
        return 0;
}
原文地址:https://www.cnblogs.com/dixiao/p/13714605.html