标签:tran 表示 transform scan 目的 define 序列 email lld
构造一个长度为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\n");return 0;} } printf("Yes\n"); for(ll i=1;i<=n;i++) printf("%lld ",query(1,i,i)); return 0; }
标签:tran 表示 transform scan 目的 define 序列 email lld
原文地址:https://www.cnblogs.com/NSD-email0820/p/9692002.html