分析:or操作只有在结果的这一位为0的情况下才会强制要求两个数的这一位都为0,其它时候不强求,所以为了最大限度地满足条件,我们先把所有的数的所有位全部变成1,如果p的第i位为0,那么[l,r]的数的第i位都要为0,&一下p就好了.最后检验一下看看是否满足所有条件就可以了。为什么这样做事合法的呢?因为我们之前已经尽可能让它最大限度地满足条件了,某一位更改后可能就不能满足这么多条件了,如果这都不行,那么肯定无解.因为是区间&操作,所以用线段树来优化.
构造题要满足所有的条件,那么就构造出尽可能多地满足条件的,最后检验一下就可以了.
注意:实际操作是|,但是每次进行的操作是&,在合并和修改的时候不要弄混了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int inf = (1 << 30) - 1, maxn = 300010; int n, m, l[maxn], r[maxn], p[maxn], v[maxn * 4], tag[maxn * 4], flag[maxn * 4]; bool can = true; void build(int o, int l, int r) { tag[o] = v[o] = inf; if (l == r) return; int mid = (l + r) >> 1; build(o * 2, l, mid); build(o * 2 + 1, mid + 1, r); } void pushup(int o) { v[o] = v[o * 2] | v[o * 2 + 1]; } void pushdown(int o) { if (flag[o]) { flag[o * 2] = flag[o * 2 + 1] = 1; flag[o] = 0; tag[o * 2] &= tag[o]; tag[o * 2 + 1] &= tag[o]; v[o * 2] &= tag[o]; v[o * 2 + 1] &= tag[o]; tag[o] = inf; } } void update(int o, int l, int r, int x, int y, int c) { if (x <= l && r <= y) { tag[o] &= c; v[o] &= c; flag[o] = 1; return; } pushdown(o); int mid = (l + r) >> 1; if (x <= mid) update(o * 2, l, mid, x, y, c); if (y > mid) update(o * 2 + 1, mid + 1, r, x, y, c); pushup(o); } int query(int o, int l, int r, int x, int y) { if (x <= l && r <= y) return v[o]; pushdown(o); int mid = (l + r) >> 1, res = 0; if (x <= mid) res |= query(o * 2, l, mid, x, y); if (y > mid) res |= query(o * 2 + 1, mid + 1, r, x, y); return res; } int main() { freopen("or1.in", "r", stdin); freopen("or2.txt", "w", stdout); scanf("%d%d", &n, &m); build(1, 1, n); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &l[i], &r[i], &p[i]); update(1, 1, n, l[i], r[i], p[i]); } for (int i = 1; i <= m; i++) if (query(1, 1, n, l[i], r[i]) != p[i]) { can = 0; break; } if (can == false) printf("No "); else { printf("Yes "); for (int i = 1; i <= n; i++) printf("%d ",query(1,1,n,i,i)); } return 0; }