区间修改lazy线段树

开关灯
lites
[问题描述]
Farmer John尝试通过和奶牛们玩益智玩具来保持奶牛们思维敏
捷。 其中一个大型玩具是牛栏中的灯, N (2 <=N <=100,000) 头
奶牛被连续的编号为1..N,每头牛都站在一个彩色的灯下面。
刚到傍晚的时候, 所有的灯都是关闭的。 奶牛们通过N个按钮来
控制灯的开关, 按第i个按钮可以改变第i个灯的状态。奶牛们执行M
(1 <=M <=100,000)条指令,指令共有两种,第1种指令用0表示,指
令里包含两个数字S_i和E_i (1 <=S_i <=E_i <=N),表示奶牛们
只需要把从S_i到E_i之间的按钮都按一次就可以完成这个指令。第2种
指令用1表示,同样包含两个数字S_i和E_i (1 <=S_i <=E_i <=
N), 不过这种指令是询问从S_i到E_i之间有多少灯是亮着的。请你帮
助奶牛们得到正确的答案。
[输⼊]
第 1 行:用空格隔开的两个整数N和M。
第 2..M+1 行:每行表示一个操作, 有三个用空格分开的整数: 指令,
S_i 和 E_i。
[输出]
第 1..询问的次数行:对于每一次询问,输出询问的结果。
样例输⼊ 样例输出
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
1
2

lazy操作模板:

#include<stdio.h>
#include<iostream>
#define goback(x) ((x==true)?(false):(true))
using namespace std;
const int MAX_N = 100050;
const int root = 1;
struct node
{
	int ID;
	int L,R;
	int Lid,Rid;
	bool fback;
	int sum ;
};
struct node T[MAX_N*2];
int N,M;
int times = 0;
void Build(int l,int r)
{
	if (l>r) return ;
	if (l==r)
	{
		times++;
		T[times]=(struct node){times,l,r,-1,-1,false,0};
		return ;
	}
	int mid=(l+r)/2;
	int now=++times;
	int lid=times+1;
	Build(l,mid);
	int rid=times+1;
	Build(mid+1,r);
	T[now]=(struct node){now,l,r,lid,rid,false,0};
}
void init()
{
	scanf("%d %d",&N,&M);
	Build(1,N);
}
int solve(int t,int s,int e)
{
	int l=T[t].L;
	int r=T[t].R;
	int mid=(l+r)/2;
	if (s>r) return 0;
	if (e<l) return 0;
	if (t==-1) return 0;
	if (s<=l&&e>=r) return T[t].sum;
	if (T[t].fback)
	{
		T[t].fback=goback(T[t].fback);
		T[T[t].Lid].fback=goback(T[T[t].Lid].fback);
		T[T[t].Rid].fback=goback(T[T[t].Rid].fback);
		T[T[t].Lid].sum=T[T[t].Lid].R-T[T[t].Lid].L+1-T[T[t].Lid].sum;
		T[T[t].Rid].sum=T[T[t].Rid].R-T[T[t].Rid].L+1-T[T[t].Rid].sum;
	}
	if (e<=mid)
			return solve(T[t].Lid,s,e);
		else if (s>mid)
			return solve(T[t].Rid,s,e);
		else return solve(T[t].Lid,s,mid)+solve(T[t].Rid,mid+1,e);
}
int change(int t,int s,int e)
{
	int l=T[t].L;
	int r=T[t].R;
	int mid=(l+r)/2;
	if (t==-1) return 0;
	if (s>r) return 0;
	if (e<l) return 0;
	if (s<=l&&e>=r)
	{
		T[t].fback=goback(T[t].fback);
		T[t].sum=T[t].R-T[t].L+1-T[t].sum;
		return T[t].sum;
	}
	if (T[t].fback)
	{
		T[t].fback=goback(T[t].fback);
		T[T[t].Lid].fback=goback(T[T[t].Lid].fback);
		T[T[t].Rid].fback=goback(T[T[t].Rid].fback);
		T[T[t].Lid].sum=T[T[t].Lid].R-T[T[t].Lid].L+1-T[T[t].Lid].sum;
		T[T[t].Rid].sum=T[T[t].Rid].R-T[T[t].Rid].L+1-T[T[t].Rid].sum;
	}
	if (e<=mid)
			change(T[t].Lid,s,e);
		else if (s>mid)
			change(T[t].Rid,s,e);
		else change(T[t].Lid,s,mid),change(T[t].Rid,mid+1,e);
	T[t].sum=T[T[t].Lid].sum+T[T[t].Rid].sum;
	return T[t].sum;
}
void work_put()
{
	int i;
	int Q,A,B;
	for (i=1;i<=M;i++)
	{
		scanf("%d %d %d",&Q,&A,&B);
		if (Q==0)
			change(root,A,B);
		if (Q==1)
			printf("%d\n",solve(root,A,B));
	}
}
int main()
{
	freopen("lites.in","r",stdin);
	freopen("lites.out","w",stdout);
	init();
	work_put();
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值