【或位运算】【构造】
题面
算法
关于这种有关二进制位的运算
我们照例是对每一位进行考虑
我们先把要构造的数列 \(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;
}