[2018.10.15 T1] 或

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/83068182

暂无连接

【题目描述】

小Q非常喜欢序列和位运算。

有一天,小Q想到了一个模型:一个长度为 n n 的非负整数序列 x x ,满足 m m 个条件:第 i i 个条件为 x [ l i ]   o r   x [ l i + 1 ]   o r     o r   x [ r i ] = p i x[l_i]\ or\ x[l_{i+1}]\ or\ \cdots\ or\ x[r_i]=p_i 。他想知道是否存在一个序列满足条件,如果存在,他还要构造出一个这样的序列。

【输入】

第一行两个整数 n , m n,m 。接下来 m m 行每行三个整数 l i , r i , p i l_i,r_i,p_i

【输出】

如果存在这样的序列 x x ,第一行输出Yes,第二行输出 n n 个不超过 2 30 1 2^{30}−1 的非负整数表示 x [ 1 ]   x [ n ] x[1]\sim ~x[n] ,否则输出一行 N o No

【输入样例】

2 1
1 2 1

【输出样例】

Yes
1 1

【提示】
【数据规模及约定】

对于 30 % 30\% 的数据, n , m 1000 n,m≤1000
对于另外 30 % 30\% 的数据, p i 1 p_i≤1
对于 100 % 100\% 的数据, n , m 100 , 000 1 l i r i n 0 p i < 2 30 n,m≤100,000,1≤l_i≤r_i≤n,0≤p_i<2^{30}

题解

如果一段区间 o r or 起来某几位等于 0 0 ,那么该区间的这几位必须全部为 0 0 ,所以我们开 30 30 个序列维护每一位,通过查分做区间赋 0 0 操作。

最后按照我们构造出的每一位得出答案,用线段树 c h e c k check 一下即可。

代码
#include<bits/stdc++.h>
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=1e5+5,bit=30;
int que[bit+2][M],ans[M],sum[M<<2],l[M],r[M],p[M],n,m;
void in(){scanf("%d%d",&n,&m);}
void up(int v){sum[v]=sum[ls]|sum[rs];}
void build(int v,int l,int r)
{
	if(l==r){sum[v]=ans[l];return;}
	int mid=l+r>>1;
	build(ls,l,mid);build(rs,mid+1,r);
	up(v);
}
int ask(int v,int le,int ri,int lb,int rb)
{
	if(lb<=le&&ri<=rb){return sum[v];}
	int mid=le+ri>>1,ans=0;
	if(lb<=mid)ans=ask(ls,le,mid,lb,rb);
	if(mid<rb)ans|=ask(rs,mid+1,ri,lb,rb);
	return ans;
}
void ac()
{
	for(int i=0;i<bit;++i)que[i][0]=1;
	for(int i=1,j;i<=m;++i)
	{
		scanf("%d%d%d",&l[i],&r[i],&p[i]);
		for(j=0;j<bit;++j)
		if(!(p[i]>>j&1))--que[j][l[i]],++que[j][r[i]+1];
	}
	for(int i=0,j;i<bit;++i)for(j=1;j<=n;++j)que[i][j]+=que[i][j-1];
	for(int i=0,j;i<bit;++i)for(j=1;j<=n;++j)if(que[i][j]==1)ans[j]|=1<<i;
	build(1,1,n);
	for(int i=1;i<=m;++i)if(ask(1,1,n,l[i],r[i])!=p[i])puts("No"),exit(0);
	puts("Yes");for(int i=1;i<=n;++i)printf("%d ",ans[i]);
}
int main(){in(),ac();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/83068182
t1
今日推荐