【描述】
构造一个长度为 n 的非负整数序列 x,满足 m 个条件,第 i 个条件为
x[li] | x[li+1] | … | x[ri]=pi。
【输入】
第一行两个整数 n,m。接下来 m 行每行三个整数 li,ri,pi。
【输出】
如果存在这样的序列 x,第一行输出 Yes,第二行输出 n 个不超过 2^30-1 的非负整数表示x[1]~x[n],否则输出一行 No。
【输入样例 】
2 1
1 2 1
【输出样例 】
Yes
【子任务】
对于 30%的数据, n,m<=1000。
对于另外 30%的数据, pi<=1。
对于 100%的数据, n,m<=100000, 1<=li<=ri<=n, 0<=pi<2^30。
BB:
好的又是一道位运算。。。
怎么gonze这么喜欢考位运算。。。
因为不会卡我们常数???
好的进入主题。
解析:
这次的位运算只有一种,就是or运算。
给出限制的方式也很玄学,限制区间or的结果。。。
区间。。。emmmm…
于是开始考虑区间处理的奇技淫巧。。。
于是想到了线段树。
先看一下每一个限制对结果的实际影响:
- 各位or结果互不影响
- 若or结果中该位为1,则该区间该位必有至少一个1
- 若or结果中该位为0,则该区间所有位都为0。。
第一条,说不定可以各位分开处理(我后座的dalao,似乎建立了30颗线段树,卡常数卡出
),但是实际上不用。。
第二条,没什么屁用。
第三条,我们可以将所有数初始化为$2^{30}-1,对于每一个限制,区间and一下就好了,这样就能保证所有数在0的位上满足了限制。
但是这样可能无法满足区间中至少有一个1的条件,所以最后再次检验是否满足原限制。
总结起来,就是线段树区间and,询问区间or的结果。
还有一个小优化。就是可以在区间修改的时候记录是否合法,不合法直接输出“No”,优化效果不太强,而且调试难度较大(虽然
已经调出来了),这里就贴一个一般的算法吧。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define cs const
#define gc getchar
#define pc putchar
#define st static
#define uint unsigned int
inline
uint getint(){
st uint num;
st char c;
for(c=gc();!isdigit(c);c=gc());
for(num=0;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(uint a) {
st char ch[23];
if(a==0)return (void)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
int n,m;
const uint bas=(1<<30)-1;
uint num[400005];
uint a[100005];
inline
void build(int k,int l,int r){
num[k]=bas;
if(l==r)return ;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline
void pushdown(int k){
num[k<<1]&=num[k];
num[k<<1|1]&=num[k];
}
inline
void update(int k,int l,int r,cs int &ql,cs int &qr,cs uint &val){
if(ql<=l&&r<=qr){
num[k]&=val;
return ;
}
pushdown(k);
int mid=(l+r)>>1;
if(ql<=mid)update(k<<1,l,mid,ql,qr,val);
if(qr>mid)update(k<<1|1,mid+1,r,ql,qr,val);
}
inline
uint queryor(int k,int l,int r,cs int &ql,cs int &qr){
if(ql<=l&&r<=qr){
return num[k];
}
pushdown(k);
uint ans=0;
int mid=(l+r)>>1;
if(ql<=mid)ans|=queryor(k<<1,l,mid,ql,qr);
if(qr>mid)ans|=queryor(k<<1|1,mid+1,r,ql,qr);
return ans;
}
inline
void pushall(int k,int l,int r){
if(l==r)return (void)(a[l]=num[k]);
pushdown(k);
int mid=(l+r)>>1;
pushall(k<<1,l,mid);
pushall(k<<1|1,mid+1,r);
}
int l[100005],r[100005];
uint c[100005];
int main(){
n=getint();
m=getint();
build(1,1,n);
for(int re i=1;i<=m;++i){
l[i]=getint();
r[i]=getint();
c[i]=getint();
update(1,1,n,l[i],r[i],c[i]);
}
for(int re i=1;i<=m;++i){
if(queryor(1,1,n,l[i],r[i])!=c[i]){
puts("No");
return 0;
}
}
pushall(1,1,n);
puts("Yes");
for(int re i=1;i<=n;++i){
outint(a[i]),pc(' ');
}
return 0;
}