题意:问是否存在使得每次求并后给定区间为给定数值的序列。
思路:首先对于q转化成二进制,然后每一位如果为1,对应区间内的所有数的该位赋值为1。处理完后便生成了答案序列,再处理q的每一位如果为0的情况,如果这个区间的全为1的话,就不能构成这样的序列。
AC代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int l,r,num[30];
bool val[30];
}tree[400010];
struct node2
{
int l,r,q;
}op[100010];
int f[100010];
void build(int o,int l,int r)
{
int i,j,k,mi;
tree[o].l=l;
tree[o].r=r;
for(i=0;i<=29;i++)
tree[o].num[i]=0;
if(l==r)
{
f[l]=o;
return;
}
mi=(l+r)/2;
build(o<<1,l,mi);
build(o<<1|1,mi+1,r);
}
void down(int o)
{
if(tree[o].l!=tree[o].r)
for(int i=0;i<=29;i++)
{
if(tree[o].val[i]==1)
{
tree[o<<1].val[i]=1;tree[o<<1|1].val[i]=1;
tree[o<<1].num[i]=0;tree[o<<1|1].num[i]=0;
}
}
}
void update(int o,int l,int r,int pos)
{
down(o);
if(tree[o].l==l && tree[o].r==r)
{
tree[o].val[pos]=1;
tree[o].num[pos]=0;
return;
}
int mi=(tree[o].l+tree[o].r)/2;
if(r<=mi)
update(o<<1,l,r,pos);
else if(l>mi)
update(o<<1|1,l,r,pos);
else
{
update(o<<1,l,mi,pos);
update(o<<1|1,mi+1,r,pos);
}
tree[o].num[pos]=tree[o<<1].num[pos]+tree[o<<1|1].num[pos];
}
void down2(int o)
{
down(o);
if(tree[o].l==tree[o].r)
return;
down2(o<<1);
down2(o<<1|1);
}
int pow2[35],val[100010],num[100010][35];
int main()
{
int i,j,k,n,m,ret;
bool flag=true;
scanf("%d%d",&n,&m);
build(1,1,n);
//printf("ok\n");
for(i=1;i<=m;i++)
scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].q);
m=min(m,33);
for(i=0;i<=30;i++)
num[0][i]=0;
pow2[0]=1;
for(i=1;i<=30;i++)
pow2[i]=pow2[i-1]*2;
for(i=1;i<=m;i++)
for(j=0;j<=29;j++)
if((op[i].q&pow2[j])==0)
update(1,op[i].l,op[i].r,j);
down2(1);
for(i=1;i<=n;i++)
{
ret=0;
for(j=0;j<=29;j++)
if(tree[f[i]].num[j]==1)
{
ret+=pow2[j];
num[i][j]=num[i-1][j]+1;
}
else
num[i][j]=num[i-1][j];
val[i]=ret;
}
for(i=1;i<=m;i++)
{
for(j=0;j<=29;j++)
if((op[i].q&pow2[j])>0)
if(num[op[i].r][j]-num[op[i].l][j]==0)
flag=false;
}
if(!flag)
printf("NO\n");
else
{
printf("YES\n");
for(i=1;i<=n;i++)
printf("%d ",val[i]);
printf("\n");
}
}