CodeForces 482 B. Interesting Array

CodeForces 482 B. Interesting Array_第1张图片

题意就是,给定n,m.

求n个数,满足m个条件。

每个条件的形式是,给定 Li,Ri,Qi ,要求   a[Li]&a[Li+1]&...&a[Ri] = Qi ;

Qi 最多有30个二进制位。所以每个数都可以用int存下。

对于Qi 的每一位,

若为1,则 a[Li],a[Li+1],...,a[Ri]的这一位都必须为1;(按位或)

若为0,则 a[Li],a[Li+1],...,a[Ri]至少有一位为零;(尽量让它们全零,以免多出的几个1,使得其他区间本不应全1的出现了全1)

用线段树,将 Li 到 Ri 区间内的所有数,对Qi 进行  按位或运算。

这样可以用最少数量的1,满足:若Qi的某位为1,则区间[Li,Ri]内的所有数的这一位都是1.

但是由于不同的条件填的1可能相互影响,所以,若Qi的某位为0,则区间[Li,Ri]内的数的这一位不一定有0出现,所以要重新判断。

需再建一个线段树,来存[Li,Ri]内所有数的   &(按位与运算)。

再搜索一次所有的条件,看看是否都满足  a[Li]&a[Li+1]&...&a[Ri] = Qi ;

由于生成这n个数的时候用的是最少个数的1,所以,若不能都满足条件,则不存在满足条件的 n 个数。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define maxn 100001
using namespace std;
//线段树 
int  N,n,m;
int set[maxn<<2];
void ST_Init(){
	N=1;while(N <n+2) N <<=1;
	memset(set,0,sizeof(set));
}
void TurnOn(int L,int R,int C){
	for(int s=N+L-1,t=N+R+1;s^t^1;s>>=1,t>>=1){
		if(~s&1) set[s^1]|=C;
		if(t&1)  set[t^1]|=C;
	}
}
void ShutDown(){
	//将设置标记传递下去 
	for(int i=1;i<N;++i){
		if(set[i]){
			set[i<<1]|=set[i];
			set[i<<1|1]|=set[i];
			set[i]=0;
		}
	}
	//重建新的线段树 
	for(int i=N-1;i>0;--i){
		set[i]=set[i<<1]&set[i<<1|1];
	}
}
int Query(int L,int R){
	int ANS=-1;
	for(int s=N+L-1,t=N+R+1;s^t^1;s>>=1,t>>=1){
		if(~s&1) ANS&=set[s^1];
		if(t&1)  ANS&=set[t^1];
	}
	return ANS;
}
//记录操作
int l[maxn],r[maxn],q[maxn];
int main(void)
{
	
	while(~scanf("%d%d",&n,&m)){
		ST_Init();
		for(int i=0;i<m;++i){
			scanf("%d%d%d",&l[i],&r[i],&q[i]);
			//区间内 对q[i]进行按位或
			TurnOn(l[i],r[i],q[i]); 
		}
		//重建线段树,存区间的按位与 
		ShutDown();
		//重新判断是否符合m个条件 
		int T=0;
		for(int i=0;i<m;++i){ 
			if(Query(l[i],r[i])==q[i]) ++T;
			else break;
		}
		
		if(T==m){//如果符合m个条件,输出结果 
			printf("YES\n");
			printf("%d",set[N+1]);
			for(int i=2;i<=n;++i){
				printf(" %d",set[N+i]);
			}
			printf("\n");
		}
		else{//如果不符合m个条件,则不存在符合条件的n个数。 
			printf("NO\n");
		}
	}

return 0;
}













你可能感兴趣的:(CodeForces 482 B. Interesting Array)