首页 > 其他分享 >CF482B (拆位思想+实现)

CF482B (拆位思想+实现)

时间:2024-02-27 10:24:34浏览次数:28  
标签:CF482B 思想 int mid push && ans 区间 拆位

难度:2

看到位运算想到拆位。因为是与所以对于 \([l,r]\) 区间内在二进制下,如果它是 1 则 \([l,r]\) 区间都是 1,如果是 0 则 \([l,r]\) 区间内至少有 1 个 0。因为是区间所以不难想到用线段树处理,而线段树维护的就是区间内1的个数。

考虑如何处理。首先对于q拆位,1就为区间赋值,操作完后就找到了满足所有1的方案。再考虑有没有满足有0。如果 \([l,r]\) 区间内至少有 1 个 0,并且 \([l,r]\) 区间内都是 1,则NO,否则可以。

考虑如何实现,容易想到的是开32颗线段树时间复杂度\(32n\log n\),我也不知道为什么不能过

再考虑把32给干了。容易发现按位区间赋值其实就是区间或


下面看了题解

那处理后面其实就是将这个区间与求出来看看是否与原数一致。因为既然所有1都满足,那么1就不用考虑了,对于其他的一起处理即可


代码写起来不难

未过

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int n,m,l[100005],r[100005],q[100005],ans[100005];
inline int read(){
    char c=getchar();
    int x=0;
    while(c<48){c=getchar();}
    while(c>47)x=(x*10)+(c^48),c=getchar();
    return x;
}
inline void print(int x){
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
struct seg{
	int d[400005],la[400005];
	inline void push_up(int p){
		d[p]=d[p<<1]+d[p<<1|1];
	}
	inline void push_down(int l,int r,int p,int mid){
		if(la[p]){
			d[p<<1]=la[p]*(mid-l+1);
			d[p<<1|1]=la[p]*(r-mid);
			la[p<<1]=la[p];
			la[p<<1|1]=la[p];
			la[p]=0;
		}
	}
	inline void update(int l,int r,int p,int s,int t){
		if(l>=s&&r<=t){
			d[p]=r-l+1;
			la[p]=1;
			return;
		}
		int mid=(l+r)>>1;
		push_down(l,r,p,mid);
		if(s<=mid) update(l,mid,p<<1,s,t);
		if(t>mid) update(mid+1,r,p<<1|1,s,t);
		push_up(p);
	}
	inline int getsum(int l,int r,int p,int s,int t){
		if(l>=s&&r<=t) return d[p]; 
		int mid=(l+r)>>1,ans=0;
		push_down(l,r,p,mid);
		if(s<=mid) ans+=getsum(l,mid,p<<1,s,t);
		if(t>mid) ans+=getsum(mid+1,r,p<<1|1,s,t);
		return ans;
	}
	inline void get(int l,int r,int p,int ad){
		if(l==r){
			ans[l]+=(d[p]<<ad);
			return;
		}
		int mid=(l+r)>>1;
		push_down(l,r,p,mid);
		get(l,mid,p<<1,ad);
		get(mid+1,r,p<<1|1,ad);
	}
}s[32];
int main(){
	n=read();
	m=read();
	for(register int i=1;i<=m;i++){
		l[i]=read();
		r[i]=read();
		q[i]=read();
		for(register int j=0;(1<<j)<=q[i];j++) if(q[i]&(1<<j)) s[j].update(1,n,1,l[i],r[i]); 
	}
	for(register int i=1;i<=m;i++){
		for(register int j=0;(1<<j)<=q[i];j++){
			if(!(q[i]&(1<<j))){
				if(s[j].getsum(1,n,1,l[i],r[i])==(r[i]-l[i]+1)){
					cout<<"NO"<<endl;
					return 0;
				}
			}
		}
	}
	cout<<"YES\n";
	for(register int i=0;i<=31;i++) s[i].get(1,n,1,i); 
	for(register int i=1;i<=n;i++){
		print(ans[i]);
		putchar(' ');
	}
	
	return 0;
}//1000 1111 111

已过

#include<bits/stdc++.h>
using namespace std;
int d[400005],la[400005];
void push_up(int p){
	d[p]=d[p<<1]&d[p<<1|1];
}
void push_down(int l,int r,int p,int mid){
	if(la[p]){
		d[p<<1]|=la[p];
		d[p<<1|1]|=la[p];
		la[p<<1]|=la[p];
		la[p<<1|1]|=la[p];
		la[p]=0;
	}
}
void update(int l,int r,int p,int ad,int s,int t){
	if(l>=s&&r<=t){
		d[p]|=ad;
		la[p]|=ad;
		return;
	}
	int mid=(l+r)>>1;
	push_down(l,r,p,mid);
	if(s<=mid) update(l,mid,p<<1,ad,s,t);
	if(t>mid) update(mid+1,r,p<<1|1,ad,s,t);
	push_up(p);
}
int getsum(int l,int r,int p,int s,int t){
	if(l>=s&&r<=t){
		return d[p];
	}
	int mid=(l+r)>>1,ans=(1<<30)-1;
	push_down(l,r,p,mid);
	if(s<=mid) ans=ans&getsum(l,mid,p<<1,s,t);
	if(t>mid) ans=ans&getsum(mid+1,r,p<<1|1,s,t);
	return ans;
}
int n,m,l[100005],r[100005],q[100005],ans[100005];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>l[i]>>r[i]>>q[i];
		update(1,n,1,q[i],l[i],r[i]);
	}
	for(int i=1;i<=m;i++){
		if(getsum(1,n,1,l[i],r[i])!=q[i]){
			cout<<"NO"<<endl;
			return 0;
		}
	}
	cout<<"YES\n";
	for(int i=1;i<=n;i++){
		cout<<getsum(1,n,1,i,i)<<" ";
	}
	
	return 0;
}//1000 1111 111

标签:CF482B,思想,int,mid,push,&&,ans,区间,拆位
From: https://www.cnblogs.com/wuhupai/p/18036306

相关文章

  • P3157 (cdq分治思想)
    难度2eeeeeeeee比较有意思的一道题目。一开始看到删除,有一个很经典的trick,就是将删除变成插入,倒序处理。然后发现不会做了。然后巨佬lyc说可以用cdq分治,将时间变为第三个关键字,这样也就不用倒序处理了。考虑求出删除某个数后对逆序对个数产生的贡献,在加入了时间戳之后i,j为逆序对......
  • CF776D(并查集思想)
    难度1em还是一道比较套路的题目。观察发现,如果当\(r_{i}=1\)时他的两把钥匙状态是相同的,当\(r_{i}=0\)时他的两把钥匙状态是不同的,对于这种相同不同的问题可以考虑并差集,状态一样就一样的并在一起,否则就把不一样的并在一起所以以后看见这些问题(a=b+k,a=!b,a=b)都可以用带权并查......
  • ABC283E (dp思想)
    难度1这题看到一点思路也没有,但是看到最小操作数想到二分,dp和贪心,二分答案的check显然不会,贪心不会。发现对于一行,前面的\(i-2\)是不会影响的,这一行也不会影响后面的\(i+2\)行,所以是dp。考虑如何设计状态因为\(i-1\)和\(i+1\)行都会影响,所以设计出来一个dp[i][0/1][0/1][0/1]的东......
  • P10156(dp思想)
    难度2也是比较有意思的一道题。首先发现每个小团体独立,所以对于每个小团体分开直接暴力dp,dp[i][j]表示当前小团体做到第i人,走了j人,然后O(n)转移,加上部分分喜提50pts。为什么要O(n)转移呢,因为我要枚举匹配的两个人然后算贡献。但是对于这种带绝对值的贡献,我们一般都要把绝对值拆掉......
  • CF1928C (数学思想)
    难度3其实是有点虚高的,可能是我这种数学题做的少了。在考试时式子都写出来了,但不知道怎么处理。然后注意一下细节就可以了。懒懒懒。对于xy=k(k为常数)可以直接枚举k的因子,然后看一下限制条件即可。#include<bits/stdc++.h>usingnamespacestd;longlongT,n,x,tot=0;unorde......
  • P6805 (树上最小路径覆盖思想)
    难度3比较有意思的一道题。首先看到题目是求树上最小路径覆盖,自然想到由叶子入手去分析,所以当子树内有偶数个叶子节点时,那么就有两个叶子向上匹配,否则只有一个叶子向上匹配。这个东西可以用树剖维护,线段树维护的是子树内有多少个偶的,相当于一个区间反转一类的东西。细节不算多,但......
  • P4666 [BalticOI 2011 Day1] Growing Trees题解(平衡树思想)
    自己第一道不看题解写出来的紫题,庆祝一下(没初始化种子导致调了30min)这是一个fhq-treap的题解思路来源:首先看题目,因为是序列上的问题,不难想到是一道数据结构题。首先看到操作C:对于这种操作,我们可以用平衡树解决,具体方法是,将树split成\(<min,min\lex\lemax,>max\)这......
  • 贪心算法思想
    贪心算法每一步都找到当前局部最优解,短视,但是有思考贪心算法(GreedyAlogorithm)又叫登山算法,它的根本思想是逐步到达山顶,即逐步获得最优解,是解决最优化问题时的一种简单但是适用范围有限的策略。贪心算法没有固定的框架,算法设计的关键是贪婪策略的选择。每一步都找到最优解,由......
  • Java锁的思想和区别
    乐观锁VS悲观锁乐观锁和悲观锁是两种处理并发访问的不同策略,用于确保多个操作不会同时修改同一资源而导致数据不一致的问题。它们的区别在于处理并发时的思想和实现方式:乐观锁:思想:认为在大多数情况下,读操作远远多于写操作,因此假设在绝大多数情况下并发冲突是不会发生的,直到出......
  • 坏人的片面思想
    前文谈到了坏人的思想都是片面的,那么那些工于心计的坏人,是怎么骗到和猜中他人心思的呢?其实原因很简单,世上大部分人都是灰色人性的人,而灰色人性的特点就是虽然心存善念,但是依然自私自利,和利益至上,坏人正是抓住了他们自私和崇拜金钱的特性。在这点上他们是共通的,能感同身受。而且这......