SDOJ2820or(或)
Posted nsd-email0820
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOJ2820or(或)相关的知识,希望对你有一定的参考价值。
题面
构造一个长度为n的非负整数序列x,满足m个条件,第i个条件为x[li]|x[li+1]|…|x[ri]=pi。
输入
第一行两个整数n,m。接下来m行每行三个整数li,ri,pi。
输出
如果存在这样的序列x,第一行输出Yes,第二行输出n个不超过2^30-1的非负整数表示x[1]~x[n],否则输出一行No。
对于30%的数据,n,m<=1000。
对于另外30%的数据,pi<=1。
对于100%的数据,n,m<=100000,1<=li<=ri<=n,0<=pi<2^30。
分析
几个显然的结论
1.有0的位置必须所有数那一位全部为0
2.有1的位置必须有一个数那一位为1
所以其实可以拿p来构造,把所有数都设为230-1(二进制所有位都是1)
拿p来&一下,原来是1的位置遇到0就会被弄成0,遇到1不会变,按照题目的意思去尝试修改(区间修改,线段树)
最后需要检验一下,就区间取或
这有一个结论
(a&p)|(b&p)……(z&p)=(a|b|……|z)&p
这就是为啥线段树可以合法合并
代码
#include<bits/stdc++.h> using namespace std; #define N 100100 #define ll long long #define MAXN (1<<30)-1 #define lc (p<<1) #define rc (p<<1|1) #define mid (t[p].l+t[p].r>>1) ll n,m; ll p[N],pl[N],pr[N]; struct email { ll l,r,sum; }t[N*4]; inline void pushup(ll p) { t[p].sum=t[lc].sum|t[rc].sum; } inline void pushdown(ll p) { ll px=t[p].sum; t[lc].sum&=px;t[rc].sum&=px; } inline void build(ll p,ll l,ll r) { t[p].l=l;t[p].r=r; if(l==r) { t[p].sum=MAXN; return ; } ll bm=l+r>>1; build(lc,l,bm);build(rc,bm+1,r); pushup(p); } inline void update(ll p,ll ql,ll qr,ll x) { if(ql<=t[p].l&&qr>=t[p].r) { t[p].sum&=x; return ; } pushdown(p); if(ql<=mid)update(lc,ql,qr,x); if(qr>mid)update(rc,ql,qr,x); pushup(p); } inline ll query(ll p,ll ql,ll qr) { ll ret=0; if(ql<=t[p].l&&qr>=t[p].r) return t[p].sum; pushdown(p); if(ql<=mid)ret|=query(lc,ql,qr); if(qr>mid)ret|=query(rc,ql,qr); return ret; } int main() { scanf("%lld%lld",&n,&m); build(1,1,n); for(ll i=1;i<=m;i++) { scanf("%lld%lld%lld",&pl[i],&pr[i],&p[i]); update(1,pl[i],pr[i],p[i]); } for(ll i=1;i<=m;i++) { ll ret=query(1,pl[i],pr[i]); if(ret!=p[i]) {printf("No ");return 0;} } printf("Yes "); for(ll i=1;i<=n;i++) printf("%lld ",query(1,i,i)); return 0; }
以上是关于SDOJ2820or(或)的主要内容,如果未能解决你的问题,请参考以下文章