CF482B Interesting Array Solution

Description

给定 m m m 个三元组 ( l , r , v ) (l,r,v) (l,r,v).
判断是否存在序列 a = ( a 1 , a 2 , ⋯   , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an),满足:

  • 对每个三元组 ( l , r , v ) (l,r,v) (l,r,v),都有 and ⁡ i = l r a i = v \mathop{\operatorname{and}}\limits_{i=l}^r a_i=v i=landrai=v.

若存在,则给出任意一种方案.

Limitations

1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1n,m105
1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1lrn
0 ≤ v < 2 30 0\le v<2^{30} 0v<230

Solution

位运算对每位独立,可以拆位.
考虑 v v v 的第 i i i 位,有:

  • 若该位为 1 1 1,则 a l ∼ a r a_l\sim a_r alar 的第 i i i 位都为 1 1 1.
  • 若该位为 0 0 0,则 a l ∼ a r a_l\sim a_r alar 的第 i i i 位中至少有一个为 0 0 0.

第二个条件不好构造,我们可以只考虑第一个条件,构造完后逐个进行验证.
显然将 a l ∼ a r a_l\sim a_r alar i i i 位赋值为 1 1 1 相当于 a l ∼ a r a_l\sim a_r alar or ⁡ \operatorname{or} or 2 i 2^i 2i.
那么实现时不用拆位,直接用线段树维护 a a a,支持区间 or ⁡ \operatorname{or} or x x x,求区间 and ⁡ \operatorname{and} and 和即可.

Code

2.60 KB , 0.27 s , 700 KB    (C++20,   gcc   13,   64   bit) 2.60\text{KB},0.27\text{s},700\text{KB}\;\texttt{(C++20, gcc 13, 64 bit)} 2.60KB,0.27s,700KB(C++20, gcc 13, 64 bit)

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

constexpr int V = (1 << 30) - 1;
namespace seg_tree {
	struct Node {
		int l, r, andd, tag;
	};
	
	inline int ls(int u) { return 2 * u + 1; }
	inline int rs(int u) { return 2 * u + 2; }
	
	struct SegTree {
		vector<Node> tr;
		
		inline SegTree() {}
		inline SegTree(int _n) : tr(_n << 1) { build(0, 0, _n - 1); }
		
		inline void pushup(int u, int mid) {
			tr[u].andd = tr[ls(mid)].andd & tr[rs(mid)].andd;
		}
		
		inline void apply(int u, int tag) {
			tr[u].andd |= tag;
			tr[u].tag |= tag;
		}
		
		inline void pushdown(int u, int mid) {
			if (tr[u].tag) {
				apply(ls(mid), tr[u].tag);
				apply(rs(mid), tr[u].tag);
				tr[u].tag = 0;
			}
		}
		
		void build(int u, int l, int r) {
			tr[u].l = l, tr[u].r = r;
			if (l == r) return;
			const int mid = (l + r) >> 1;
			build(ls(mid), l, mid), build(rs(mid), mid + 1, r);
		}
		
		void update(int u, int l, int r, int k) {
			if (l <= tr[u].l && tr[u].r <= r) return apply(u, k);
			const int mid = (tr[u].l + tr[u].r) >> 1;
			pushdown(u, mid);
			if (l <= mid) update(ls(mid), l, r, k);
			if (r > mid) update(rs(mid), l, r, k);
			pushup(u, mid);
		}
		
		int query(int u, int l, int r) {
			if (l <= tr[u].l && tr[u].r <= r) return tr[u].andd;
			const int mid = (tr[u].l + tr[u].r) >> 1;
			int res = V;
			pushdown(u, mid);
			if (l <= mid) res &= query(ls(mid), l, r);
			if (r > mid) res &= query(rs(mid), l, r);
			return res;
		}
		
		inline void range_or(int l, int r, int k) { update(0, l, r, k); }
		inline int range_andsum(int l, int r) { return query(0, l, r); }
	};
}
using seg_tree::SegTree;

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	cin >> n >> m;
	
	SegTree sgt(n);
	vector<int> l(m), r(m), x(m);
	for (int i = 0; i < m; i++) {
		cin >> l[i] >> r[i] >> x[i];
		l[i]--, r[i]--;
		sgt.range_or(l[i], r[i], x[i]);
	}
	
	for (int i = 0; i < m; i++)
	    if (sgt.range_andsum(l[i], r[i]) != x[i]) {
	    	cout << "NO\n";
	    	return 0;
	    }
	
	cout << "YES\n";
	for (int i = 0; i < n; i++) cout << sgt.range_andsum(i, i) << ' ';
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值