参考了Yoangh大牛的博客
链接:http://blog.csdn.net/y990041769/article/details/40590953
题意:构建一个有n个元素的序列,满足题中给出的m条约束,即数列要满足第Li个数字到第Ri个数字的&等于Qi,如有满足的序列,输出YES,否则输出NO。
思路:如果某个位置处于不同的区间交内,那么这个位置的数字一定要等于那些区间的Qi的或,这样才能把每一位的1保存下来,处理的时候每读入一条约束,用线段树去更新,读完数据判断是否所有区间都满足约束,若满足,则在线段树内从上至下的更新答案。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1e5+2;
int ans[N];
int ii;
struct C
{
int l,r,q;
} c[100005];
struct Node
{
int l,r,s;
} tree[N*4];
void build(int l,int r,int root)
{
tree[root].l=l;
tree[root].r=r;
tree[root].s=0;
if(l==r)
return ;
int m=(l+r)>>1;
build(l,m,root<<1);
build(m+1,r,root<<1|1);
}
void update(int l,int r,int c,int root)
{
if(tree[root].l==l&&tree[root].r==r)
{
tree[root].s=tree[root].s|c;
return ;
}
int m=(tree[root].l+tree[root].r)>>1;
if(r<=m)
update(l,r,c,root<<1);
else if(l>m)
update(l,r,c,root<<1|1);
else
{
update(l,m,c,root<<1);
update(m+1,r,c,root<<1|1);
}
}
int query(int l,int r,int root)
{
if(tree[root].l==l&&tree[root].r==r)
return tree[root].s;
int m=(tree[root].l+tree[root].r)>>1;
if(r<=m)
return query(l,r,root<<1);
else if(l>m)
return query(l,r,root<<1|1);
else
return query(l,m,root<<1)&query(m+1,r,root<<1|1);
}
void solve(int root)
{
if(root!=1)
tree[root].s|=tree[root>>1].s;
if(tree[root].l==tree[root].r)
{
ans[ii]=tree[root].s;
ii++;
return ;
}
solve(root<<1);
solve(root<<1|1);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
build(1,n,1);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&c[i].l,&c[i].r,&c[i].q);
update(c[i].l,c[i].r,c[i].q,1);
}
int flag=1;
for(int i=1; i<=m; i++)
{
if(query(c[i].l,c[i].r,1)!=c[i].q)
{
flag=0;
break;
}
}
if(flag)
{
printf("YES\n");
ii=1;
solve(1);
for(int i=1; i<ii; i++)
{
if(i==1)
printf("%d",ans[i]);
else
printf(" %d",ans[i]);
}
printf("\n");
}
else
printf("NO\n");
}
return 0;
}