【题目】
题目描述:
构造一个长度为 n 的非负整数序列 x,满足 m 个条件,第 i 个条件为:x[ li ] | x[ li + 1 ] | … | x[ ri ] = pi。
输入格式:
第一行两个整数 n , m 。接下来 m 行每行三个整数 li , ri , pi。
输出格式:
如果存在这样的序列 x,第一行输出 Yes,第二行输出 n 个不超过 的非负整数表示 x[ 1 ] ~ x[ n ];否则输出一行 No
样例数据:
输入
2 1 1 2 1
输出
Yes 1 1
备注:
这道题是 SPJ
【数据范围】
对于 30% 的数据,n , m ≤ 1000。
对于另外 30% 的数据,pi ≤ 1。
对于 100% 的数据,n , m ≤ 100000,1 ≤ li ≤ ri ≤ n,0 ≤ pi < 。
【分析】
【30分(pi ≤ 1)】
如果 pi 等于 0,由于或运算是有 1 就为 1,所以此时 [ li , ri ] 都是 0;否则 [ li , ri ] 中就必须有至少一个 1。又由于我们只需构造一组可行解就行了,所以没被要求为 0 的就全赋为 1,然后判断是否符合条件即可。
区间赋值和区间查询可以用线段树维护
【100分】
由于在或运算中,每一位是互相独立的,所以我们可以从上面的做法推广到 pi > 1 的情况
就是把序列 x 中的元素和 p 都当做二进制数,初始时将 x[ i ] 的每一位都赋为 1(即为 )
按照上面的做法,对于每一个条件,在 pi 某一位为 0 时,将 [ li , ri ] 的那一位都变成 0
一个小技巧:我们可以直接对 [ li , ri ] 的每个数 & p,因为 0 & 0(或 1)都是 0,1 & 0(或 1)不变
一个性质:(a&p)|(b&p)| …… |(z&p)=(a | b | …… | z)&p
还是用线段树操作,时间复杂度O()
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define num (1<<30)-1
using namespace std;
int l[N],r[N],p[N];
int n,m,sum[N<<2],mark[N<<2];
void build(int root,int l,int r)
{
if(l==r)
{
sum[root]=num;
mark[root]=num;
return;
}
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
sum[root]=sum[root<<1]|sum[root<<1|1];
mark[root]=mark[root<<1]|mark[root<<1|1];
}
void pushdown(int root,int l,int r)
{
int mid=(l+r)>>1;
sum[root<<1]&=mark[root];
sum[root<<1|1]&=mark[root];
mark[root<<1]&=mark[root];
mark[root<<1|1]&=mark[root];
mark[root]=num;
}
void modify(int root,int l,int r,int x,int y,int p)
{
if(l>=x&&r<=y)
{
sum[root]&=p;
mark[root]&=p;
return;
}
int mid=(l+r)>>1;
if(mark[root]!=num) pushdown(root,l,r);
if(x<=mid) modify(root<<1,l,mid,x,y,p);
if(y>mid) modify(root<<1|1,mid+1,r,x,y,p);
sum[root]=sum[root<<1]|sum[root<<1|1];
}
int query(int root,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
return sum[root];
int ans=0,mid=(l+r)>>1;
if(mark[root]!=num) pushdown(root,l,r);
if(x<=mid) ans|=query(root<<1,l,mid,x,y);
if(y>mid) ans|=query(root<<1|1,mid+1,r,x,y);
return ans;
}
int main()
{
// freopen("or.in","r",stdin);
// freopen("or.out","w",stdout);
int i,ans;
scanf("%d%d",&n,&m);
build(1,1,n);
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&l[i],&r[i],&p[i]);
modify(1,1,n,l[i],r[i],p[i]);
}
for(i=1;i<=m;++i)
{
ans=query(1,1,n,l[i],r[i]);
if(ans!=p[i])
{
printf("No");
return 0;
}
}
printf("Yes\n");
for(i=1;i<=n;++i)
{
ans=query(1,1,n,i,i);
printf("%d ",ans);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}