巧妙的题目。
Interesting Array
time limit per test: 1 second
memory limit per test:256 megabytes
We’ll call an array of n non-negative integers a[1], a[2], …, a[n] interesting, if it meets m constraints. The i-th of the m constraints consists of three integers li, ri, qi (1 ≤ li ≤ ri ≤ n) meaning that value should be equal to qi.
Your task is to find any interesting array of n elements or state that such array doesn’t exist.
Expression x&y means the bitwise AND of numbers x and y. In programming languages C++, Java and Python this operation is represented as “&”, in Pascal — as “and”.
Input
The first line contains two integers n, m (1 ≤ n ≤ 105, 1 ≤ m ≤ 105) — the number of elements in the array and the number of limits.
Each of the next m lines contains three integers li, ri, qi (1 ≤ li ≤ ri ≤ n, 0 ≤ qi < 230) describing the i-th limit.
Output
If the interesting array exists, in the first line print “YES” (without the quotes) and in the second line print n integers a[1], a[2], …, a[n] (0 ≤ a[i] < 230) decribing the interesting array. If there are multiple answers, print any of them.
If the interesting array doesn’t exist, print “NO” (without the quotes) in the single line.
Examples
input
3 1
1 3 3
output
YES
3 3 3
input
3 2
1 3 3
1 3 2
output
NO
首先嘛,如果一段区间的逻辑与(&)的和为q,那么这段区间内所有的数的二进制下,所有q的二进制数为1的数位,这些数位都必须为1。
比如q=5,那么对应的二进制数为101,这样这段区间所有的数的第0和第2位都得是1。
这样的话,我们利用一个差分数组s[i][j](表示数组第i位的二进制的第j位是否得取1)。然后就可以快速的把a[1…n]这个区间所有的数求出来了(利用或运算)。
最后线段树验证区间&和就行。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
int n,m;
struct node{
int x,y,q;
}s[maxn];
int a[maxn];
int part[maxn][40];
int t[maxn<<2];
void update(int x){
t[x]=t[x<<1]&t[x<<1|1];
}
void build(int l,int r,int rt){
if (l==r){
t[rt]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
update(rt);
}
int query(int ll,int rr,int l,int r,int rt){
if (l>=ll&&r<=rr){
return t[rt];
}
int mid=(l+r)>>1;
if (rr<=mid) return query(ll,rr,l,mid,rt<<1);
else if (ll>mid) return query(ll,rr,mid+1,r,rt<<1|1);
else return query(ll,rr,l,mid,rt<<1)&query(ll,rr,mid+1,r,rt<<1|1);
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for (int i=1;i<=m;i++){
cin>>s[i].x>>s[i].y>>s[i].q;
}
//差分过程
for (int i=1;i<=m;i++){
for (int j=0;j<30;j++){
if (s[i].q&(1<<j)){
part[s[i].x][j]++;
part[s[i].y+1][j]--;
}
}
}
//求a[i]
for (int j=0;j<30;j++){
for (int i=1;i<=n;i++){
part[i][j]+=part[i-1][j];
if (part[i][j]) a[i]=a[i]|(1<<j);
}
}
//线段树验证
build(1,n,1);
for (int i=1;i<=m;i++){
int x=query(s[i].x,s[i].y,1,n,1);
if (x!=s[i].q) {
cout<<"NO\n";
return 0;
}
}
cout<<"YES\n";
for (int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
return 0;
}