题意: 构造一个序列,满足m个形如:[l,r,c] 的条件。 [l,r,c]表示[l,r]中的元素按位与(&)的和为c。
解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的按位与和至少为多少。
更新时,如果val的pos位为1,那么整个区间的按位与和pos位也应该为1,否则与出来就不对了。(这是本题解题的核心)
那么此时更新 sum[rt] |= val 即可。然后再check一遍看是否满足所有条件即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 100007 int sum[*N],mark[*N]; void pushup(int rt)
{
sum[rt] = sum[*rt]&sum[*rt+];
} void pushdown(int l,int r,int rt)
{
if(mark[rt])
{
mark[*rt] |= mark[rt];
mark[*rt+] |= mark[rt];
sum[*rt] |= mark[rt];
sum[*rt+] |= mark[rt];
mark[rt] = ;
}
} void build(int l,int r,int rt)
{
mark[rt] = sum[rt] = ;
if(l == r)
return;
int mid = (l+r)/;
build(l,mid,*rt);
build(mid+,r,*rt+);
} void update(int l,int r,int aa,int bb,int val,int rt)
{
if(aa <= l && bb >= r)
{
sum[rt] |= val;
mark[rt] |= val;
return;
}
pushdown(l,r,rt);
int mid = (l+r)/;
if(aa <= mid) update(l,mid,aa,bb,val,*rt);
if(bb > mid) update(mid+,r,aa,bb,val,*rt+);
pushup(rt);
} int query(int l,int r,int aa,int bb,int rt)
{
if(aa <= l && bb >= r)
return sum[rt];
pushdown(l,r,rt);
int mid = (l+r)/;
if(bb <= mid) return query(l,mid,aa,bb,*rt);
else if(aa > mid) return query(mid+,r,aa,bb,*rt+);
else return (query(l,mid,aa,bb,*rt)&query(mid+,r,aa,bb,*rt+));
} void print(int l,int r,int rt)
{
if(l == r)
{
printf("%d ",sum[rt]);
return;
}
pushdown(l,r,rt);
int mid = (l+r)/;
print(l,mid,*rt);
print(mid+,r,*rt+);
} struct Q
{
int l,r,val;
}q[N]; int main()
{
int n,m,i;
while(scanf("%d%d",&n,&m)!=EOF)
{
build(,n,);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].val);
update(,n,q[i].l,q[i].r,q[i].val,);
}
for(i=;i<=m;i++)
{
if(query(,n,q[i].l,q[i].r,) != q[i].val)
break;
}
if(i == m+)
puts("YES"),print(,n,),puts("");
else
puts("NO");
}
return ;
}