【2018/08/22测试T2】【SDOJ 2820】or

【题目】

题目描述:

构造一个长度为 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
1 1

备注:

这道题是 SPJ

扫描二维码关注公众号,回复: 3092890 查看本文章

【数据范围】 

对于 30% 的数据,n , m ≤ 1000。 
对于另外 30% 的数据,pi ≤ 1。 
对于 100% 的数据,n , m ≤ 100000,1 ≤ li ≤ ri ≤ n,0 ≤ pi < 2^{30}。 

【分析】

【30分(pi ≤ 1)】

如果 pi 等于 0,由于或运算是有 1 就为 1,所以此时 [ li , ri ] 都是 0;否则 [ li , ri ] 中就必须有至少一个 1。又由于我们只需构造一组可行解就行了,所以没被要求为 0 的就全赋为 1,然后判断是否符合条件即可。

区间赋值和区间查询可以用线段树维护

【100分】

由于在或运算中,每一位是互相独立的,所以我们可以从上面的做法推广到 pi > 1 的情况

就是把序列 x 中的元素和 p 都当做二进制数,初始时将 x[ i ] 的每一位都赋为 1(即为 2^{30}-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(m\cdot log\, n

【代码】

#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;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81942736