2017-10-22模拟赛T2 或(or.*)

时间:2022-12-17 08:39:00

题面


【题目描述】
你需要构造一个长度为 n 的数列 X,当中的数字范围从 0 到 2^30-1。除此之外你需要
满足 m 个条件,第 i 个条件为 X[li]|X[li+1]|……|X[ri]=pi。|为按位或运算。
【输入描述】
第一行输入两个整数 n,m
接下来的 m 行每行输入三个整数 li,ri,pi
【输出描述】
如果存在这样的序列,第一行输出 Yes,否则输出 No。
如果存在这样的序列,第二行输出 n 个数,为数列 X。
【样例】
输入
2 1
1 2 1

输出
Yes
1 1
【数据范围】
对于 30%的数据,n,m<=1000。
对于另外 30%的数据,pi<=1。
对于 100%的数据,n,m<=100000,1<=li<=ri<=n,0<=pi<2^30。

题解


又是一道位运算的题目(感觉是最简单的一道……)

题意还是比较清楚的,这里不细说了。

"对于另外30%的数据",出题人在这里是不是给了一个小小的提示?

众所周知,位运算有一个性质,即对于每一个位是独立的,因此想到分开考虑每个位的情况。

对于每个条件的pi的每一位,如果这一位为0,那么这个区间内所有的数的这一位显然都为0。

因此想到如下做法:

先把数列内所有数设为230-1。

对于每个条件的pi的每一位,如果这一位为0,那么将该区间内所有数的这一位置0,最后判断每个条件是否成立即可。

用线段树维护数列,只需记录区间内所有数的或即可。复杂度O(mlog2n)

具体细节见代码。关于位运算的操作,这里不多说了。

代码


2017-10-22模拟赛T2 或(or.*)2017-10-22模拟赛T2 或(or.*)
 1 #include <stdio.h>
 2 #define N 100010
 3 #define reg register
 4 const int pv=(1<<30)-1;
 5 int n,m,l[N],r[N],a[N];
 6 struct node{int o,l;}t[270000];
 7 void build(int l,int r,int k) {
 8     t[k].o=pv;t[k].l=0;
 9     if(l!=r) {
10         build(l,l+r>>1,k<<1);
11         build((l+r>>1)+1,r,k<<1|1);
12     }
13 }
14 void pushdown(int k) {
15     reg int x=t[k].l;
16     t[k<<1].o&=~x;
17     t[k<<1].l|=x;
18     t[k<<1|1].o&=~x;
19     t[k<<1|1].l|=x;
20     t[k].l=0;
21 }
22 void setzero(int l,int r,int a,int b,int c,int k) {
23     if(l==a&&r==b) {
24         t[k].o&=~c;t[k].l|=c;
25         return;
26     }
27     pushdown(k);
28     reg int mid=l+r>>1;
29     if(b<=mid) setzero(l,mid,a,b,c,k<<1);
30     else if(a>mid) setzero(mid+1,r,a,b,c,k<<1|1);
31     else {
32         setzero(l,mid,a,mid,c,k<<1);
33         setzero(mid+1,r,mid+1,b,c,k<<1|1);
34     }
35 }
36 int query(int l,int r,int a,int b,int k) {
37     if(l==a&&r==b) return t[k].o;
38     pushdown(k);
39     reg int mid=l+r>>1;
40     if(b<=mid) return query(l,mid,a,b,k<<1);
41     else if(a>mid) return query(mid+1,r,a,b,k<<1|1);
42     else {
43         return query(l,mid,a,mid,k<<1)|query(mid+1,r,mid+1,b,k<<1|1);
44     }
45 }
46 void output(int l,int r,int k) {
47     if(l==r) {
48         printf("%d ",t[k].o);
49         return;
50     }
51     pushdown(k);
52     output(l,l+r>>1,k<<1);
53     output((l+r>>1)+1,r,k<<1|1);
54 }
55 int main() {
56     scanf("%d%d",&n,&m);
57     build(1,n,1);
58     for(int i=0;i<m;++i) {
59         scanf("%d%d%d",l+i,r+i,a+i);
60         setzero(1,n,l[i],r[i],~a[i],1);
61     }
62     for(int i=0;i<m;++i) {
63         if(query(1,n,l[i],r[i],1)!=a[i]) {
64             puts("No");
65             return 0;
66         }
67     }
68     puts("Yes");
69     output(1,n,1);
70     return 0;
71 }
View Code