1. 程式人生 > >[2018.10.15 T1] 或

[2018.10.15 T1] 或

暫無連線

【題目描述】

小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();}