题解 CF482B 【Interesting Array】

ljc20020730

2019-07-29 10:40:51

Solution

### Hint 看到题解区都是$O(n log_2^2 n )$的线段树算法,其实本题是有$O(n log_2 n)$写法的并且不用线段树。 ### 正文 #### 题意 > 给出若干个要求,$l_i , r_i , q_i$表示$a[l_i] \& a[l_i + 1]\& ... \& a[r_i] = q_i$ > > 如果存在数组$a$则输出一行$YES$然后输出一种合法的数组. 否则,输出一行$NO$. > > 对于100%的数据 $\leq n\leq 10^5 , q_i \leq 2^{30}$ #### 解析 可以把每个二进制为拉出来,对每一个位分别处理 如果一个区间$l,r$ 区间 $ and $ 值为1,那么 说明这个区间必须全部是$1$ 所以我们直接对这个区间赋值为$1$即可。 然后对每个询问做一遍check,判断是否合法,即看看是$0$位置上的$l,r$是不是都是$1$,一旦都是1,那么就前后矛盾,输出$NO$. 上述维护可以使用差分前缀和维护。复杂度是$O(n \ log_2 \ n)$ #### 程序 ```cpp # include<bits/stdc++.h> # define int long long using namespace std; const int N=1e5+10; int n,Q,c[31][N],ans[31][N]; struct rec{ int l,r,d; }q[N]; void update(int l,int r,int d) { for (int i=30;i>=0;i--) if (d&(1ll<<i)) c[i][l]++,c[i][r+1]--; } void init() { for (int i=0;i<=30;i++) for (int j=1;j<=n;j++) c[i][j]=c[i][j-1]+c[i][j]; for (int i=0;i<=30;i++) for (int j=1;j<=n;j++) c[i][j]=(c[i][j]>0); memcpy(ans,c,sizeof(c)); for (int i=0;i<=30;i++) for (int j=1;j<=n;j++) c[i][j]=c[i][j-1]+c[i][j]; } bool check(int l,int r,int d) { for (int i=30;i>=0;i--) if ((!(d&(1ll<<i)))&&(c[i][r]-c[i][l-1]==r-l+1)) return false; return true; } signed main() { scanf("%lld%lld",&n,&Q); for (int i=1;i<=Q;i++) { scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].d); update(q[i].l,q[i].r,q[i].d); } init(); for (int i=1;i<=Q;i++) if (!check(q[i].l,q[i].r,q[i].d)) { puts("NO"); return 0; } puts("YES"); for (int i=1;i<=n;i++) { int ret=0; for (int j=0;j<=30;j++) if (ans[j][i]) ret+=(1<<j); printf("%lld ",ret); } return 0; } ```