牛课月赛9-红球进黑洞-(多个线段树+异或)

这篇博客探讨了如何使用线段树解决区间异或、或、与操作的问题。通过建立不同类型的线段树,如20线段树,实现了对每个位上的1进行计数,从而快速处理区间查询和更新。文章还提供了区间异或、或、与操作的代码实现,并给出了区间最大值查询的AndRMQ问题的解决方案。总结强调了深入思考和理解数据结构在算法中的重要性。
摘要由CSDN通过智能技术生成

C

题意:
就是给你两个操作,一种是查询l到r的和,一种是让l到r都异或X。

思考:
就是建立20线段树,看看每一位有多少个1就行了。
同时类似的题目有区间或:RMQ
还有区间与:And RMQ

代码:

区间异或代码:

int T,n,m,k;
int va[N];
int cnt[N];

struct Node{
	int L,R;
	int laz;
	int sum;
};

struct segtree
{
	int now;
	Node t[4*N];
	void pushdown(int node)
	{
		int laz = t[node].laz;
		if(laz)
		{
			t[node_l].laz ^= laz;
			t[node_l].sum = (t[node_l].R-t[node_l].L+1)-t[node_l].sum;
			t[node_r].laz ^= laz;
			t[node_r].sum = (t[node_r].R-t[node_r].L+1)-t[node_r].sum;
			t[node].laz ^= 1;
		}
		return ;
	}
	void build(int node,int l,int r)
	{
		t[node].L = l,t[node].R = r;
		if(l==r)
		{
			t[node].sum = (va[l]>>now&1);
			return ;
		}
		int mid = l+r>>1;
		build(node_l,l,mid);build(node_r,mid+1,r);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	void update(int node,int l,int r,int value)
	{
		if(t[node].L>=l&&t[node].R<=r)
		{
			t[node].sum = (t[node].R-t[node].L+1)-t[node].sum;
			t[node].laz ^= value;
			return ;
		}
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(l<=mid) update(node_l,l,r,value);
		if(r>mid) update(node_r,l,r,value);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	int query(int node,int l,int r)
	{
		if(t[node].L>=l&&t[node].R<=r) return t[node].sum;
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(r<=mid) return query(node_l,l,r);
		else if(l>mid) return query(node_r,l,r);
		else return query(node_l,l,mid)+query(node_r,mid+1,r);
	}
}tr[25];

signed main()
{
	IOS;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>va[i];
	for(int i=0;i<=22;i++) 
	{
		tr[i].now = i;
		tr[i].build(1,1,n);
	}
	while(m--)
	{
		int op,a,b,c;
		cin>>op>>a>>b;
		if(op==1)
		{
			int ans = 0;
			for(int i=0;i<=22;i++)
			ans += tr[i].query(1,a,b)*(1ll<<i);
			cout<<ans<<"\n";
		}
		else
		{
			cin>>c;
			for(int i=0;i<=22;i++)
			{
				if(!(c>>i&1)) continue;
				tr[i].update(1,a,b,1);
			}
		}
	}
	return 0;
}

区间或代码:
 
int T,n,m,k;
int va[N];
int cnt[N];

struct Node{
	int L,R;
	int laz;
	int sum;
};

struct segtree
{
	int now;
	Node t[4*N];
	void pushdown(int node)
	{
		int laz = t[node].laz;
		if(laz)
		{
			t[node_l].laz = 1;
			t[node_l].sum = (t[node_l].R-t[node_l].L+1);
			t[node_r].laz = 1;
			t[node_r].sum = (t[node_r].R-t[node_r].L+1);
			t[node].laz = 0;
		}
		return ;
	}
	void build(int node,int l,int r)
	{
		t[node].L = l,t[node].R = r;
		if(l==r)
		{
			t[node].sum = (va[l]>>now&1);
			return ;
		}
		int mid = l+r>>1;
		build(node_l,l,mid);build(node_r,mid+1,r);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	void update(int node,int l,int r,int value)
	{
		if(t[node].L>=l&&t[node].R<=r)
		{
			t[node].sum = (t[node].R-t[node].L+1);
			t[node].laz = value;
			return ;
		}
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(l<=mid) update(node_l,l,r,value);
		if(r>mid) update(node_r,l,r,value);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	int query(int node,int l,int r)
	{
		if(t[node].L>=l&&t[node].R<=r) return t[node].sum;
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(r<=mid) return query(node_l,l,r);
		else if(l>mid) return query(node_r,l,r);
		else return query(node_l,l,mid)+query(node_r,mid+1,r);
	}
}tr[25];

signed main()
{
	IOS;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>va[i];
	for(int i=0;i<=22;i++) 
	{
		tr[i].now = i;
		tr[i].build(1,1,n);
	}
	while(m--)
	{
		string op;
		int a,b,c;
		cin>>op>>a>>b;
		if(op=="SUM")
		{
			ll ans = 0;
			for(int i=0;i<=22;i++)
			ans += tr[i].query(1,a,b)*(1ll<<i);
			cout<<ans<<"\n";
		}
		else
		{
			cin>>c;
			for(int i=0;i<=22;i++)
			{
				if(!(c>>i&1)) continue;
				tr[i].update(1,a,b,1);
			}
		}
	}
	return 0;
}

区间与代码:
int T,n,m,k;
int va[N];
int cnt[N];

struct Node{
	int L,R;
	int laz;
	int sum;
};

struct segtree
{
	int now;
	Node t[4*N];
	void pushdown(int node)
	{
		int laz = t[node].laz;
		if(laz)
		{
			t[node_l].laz = 1;
			t[node_l].sum = 0;
			t[node_r].laz = 1;
			t[node_r].sum = 0;
			t[node].laz = 0;
		}
		return ;
	}
	void build(int node,int l,int r)
	{
		t[node].L = l,t[node].R = r;
		if(l==r)
		{
			t[node].sum = (va[l]>>now&1);
			return ;
		}
		int mid = l+r>>1;
		build(node_l,l,mid);build(node_r,mid+1,r);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	void update(int node,int l,int r,int value)
	{
		if(t[node].L>=l&&t[node].R<=r)
		{
			t[node].sum = 0;
			t[node].laz = value;
			return ;
		}
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(l<=mid) update(node_l,l,r,value);
		if(r>mid) update(node_r,l,r,value);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	void change(int node,int x,int value)
	{
		if(t[node].L==x&&t[node].R==x)
		{
			t[node].sum = value;
			return ;
		}
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(x<=mid) change(node_l,x,value);
		else change(node_r,x,value);
		t[node].sum = t[node_l].sum+t[node_r].sum;
	}
	int query(int node,int l,int r)
	{
		if(t[node].L>=l&&t[node].R<=r) return t[node].sum;
		pushdown(node);
		int mid = (t[node].L+t[node].R)>>1;
		if(r<=mid) return query(node_l,l,r);
		else if(l>mid) return query(node_r,l,r);
		else return query(node_l,l,mid)+query(node_r,mid+1,r);
	}
}tr[32];

signed main()
{
	IOS;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>va[i];
	for(int i=0;i<=30;i++) 
	{
		tr[i].now = i;
		tr[i].build(1,1,n);
	}
	while(m--)
	{
		string op;
		int a,b,c;
		cin>>op>>a>>b;
		if(op=="AND")
		{
			cin>>c;
			for(int i=0;i<=30;i++)
			{
				if((c>>i&1)) continue;
				tr[i].update(1,a,b,1);
			}	
		}
		if(op=="UPD")
		{
			for(int i=0;i<=30;i++)
			tr[i].change(1,a,(b>>i&1));
		}
		if(op=="QUE")
		{
			int ans = 0;
			for(int i=0;i<=30;i++)
			ans += tr[i].query(1,a,b)*(1ll<<i);
			cout<<ans<<"\n";
		}
	}
	return 0;
}

And RMQ的真正题意是求的区间最大值:

struct Node{
	int L,R;
	int sum;
	int maxn;
}t[4*N];

int T,n,m,k;
int va[N];

void build(int node,int l,int r)
{
	t[node].L = l,t[node].R = r;
	if(l==r)
	{
		t[node].sum = va[l];
		t[node].maxn = va[l];
		return ;
	}
	int mid = l+r>>1;
	build(node_l,l,mid);
	build(node_r,mid+1,r);
	t[node].sum = t[node_l].sum|t[node_r].sum;
	t[node].maxn = max(t[node_l].maxn,t[node_r].maxn);
}

void update1(int node,int x,int value)
{
	if(t[node].L>x||t[node].R<x) return ;
	if(t[node].L==x&&t[node].R==x)
	{
		t[node].sum = value;
		t[node].maxn = value;
		return ;
	}
	update1(node_l,x,value);
	update1(node_r,x,value);
	t[node].sum = t[node_l].sum|t[node_r].sum;
	t[node].maxn = max(t[node_l].maxn,t[node_r].maxn);
}

void update2(int node,int l,int r,int value)
{
	if(t[node].L>r||t[node].R<l) return ;
	if(t[node].L==t[node].R)
	{
		t[node].sum &= value;
		t[node].maxn &= value;
		return ;
	}
	if((value&t[node].sum)==t[node].sum) return ;
	update2(node_l,l,r,value);
	update2(node_r,l,r,value);
	t[node].sum = t[node_l].sum|t[node_r].sum;
	t[node].maxn = max(t[node_l].maxn,t[node_r].maxn);
}

int query(int node,int l,int r)
{
	if(t[node].L>r||t[node].R<l) return -inf;
	if(t[node].L>=l&&t[node].R<=r) return t[node].maxn;
	int mid = l+r>>1;
	return max(query(node_l,l,r),query(node_r,l,r));
}

signed main()
{
	IOS;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>va[i];
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		string op;
		cin>>op;
		if(op=="AND")
		{
			int a,b,c;
			cin>>a>>b>>c;
			update2(1,a,b,c);
		}
		if(op=="UPD")
		{
			int a,b;
			cin>>a>>b;
			update1(1,a,b);
		}
		if(op=="QUE")
		{
			int a,b;
			cin>>a>>b;
			cout<<query(1,a,b)<<"\n";
		}
	}
	return 0;
}

总结:
多多思考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值