线段树 维护区间 覆盖 , 区间异或 ‘^' (待续)

本文介绍了如何使用线段树来高效地维护区间覆盖问题和区间异或操作。对于区间覆盖,线段树能以O(logN)的时间复杂度查询任意区间被标记的数量,适用于LCA和树链剖分等问题。而在区间异或操作中,线段树支持单点修改和区间查询,提供快速的区间异或和计算。

线段树维护区间  覆盖 :

现在有需求

有一个长度N序列   (* N只要符合我们的线段树复杂度都可以进行维护,而只要能维护出来,基本上都是可用线段树解决

要对区间 进行标记,标记M段 区间区间可以产生覆盖

求 任意  区间内 被标记的数量

 

直接维护区间标记是O(N)的复杂度 , 使用线段树花费O(logN) ,则应用到这种类型的结构的题可过。

some 用途列举:

  • LCA , 对u , v 两点间的路径都进行标记
  • 树链剖分 , 对u, v 两点间的路径进行记录
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <stack>
#define Clear( x , y ) memset( x , y , sizeof(x) );
#define Qcin() std::ios::sync_with_stdio(false);
using namespace std;
typedef long long LL;
const int Maxn = 1e6 + 7;
const int Inf = 1e9 + 7;
LL A[Maxn];
LL N , M;
struct edge{
	LL l , r;
	LL state , sum , lazy;
}tree[Maxn];

void PushUp( LL x ){
	tree[x].sum = max(tree[x].sum , tree[x*2].sum + tree[x*2+1].sum);
}

void Build( LL l , LL r , LL x ){
	tree[x].l = l , tree[x].r = r;
	if( l == r ){
		tree[x].state = A[l];
		tree[x].sum  = tree[x].lazy = 0;
		return;
	}
	LL mid = ( l + r ) / 2;
	Build( l , mid , x * 2 );
	Build( mid + 1 , r , x * 2 + 1 );
	PushUp( x );
}

void PushDown( LL x ){
	tree[x*2].lazy |= tree[x].lazy;
	tree[x*2+1].lazy |= tree[x].lazy;
	tree[x*2].state |= tree[x*2].lazy;
	tree[x*2+1].state |= tree[x*2+1].lazy;
	tree[x].lazy = 0;
}

void Update_line( LL L , LL R , LL add , LL x ){
	if( L <= tree[x].l && tree[x].r <= R ){
		tree[x].state |= add;
		tree[x].lazy |= add;
		tree[x].sum = tree[x].r - tree[x].l + 1;
		return;
	}
	PushDown( x );
	LL mid = ( tree[x].l + tree[x].r ) / 2;
	if( L <= mid )	Update_line( L , R , add , x * 2 );
	if( R > mid )	Update_line( L , R , add , x * 2 + 1 );
	PushUp( x );
}

LL Query( LL L , LL R , LL x ){
	if( L <= tree[x].l && tree[x].r <= R ){
		return tree[x].sum;
	}
	PushDown( x );
	LL mid = ( tree[x].l + tree[x].r ) / 2;
	LL res = 0LL;
	if( L <= mid )	res += Query( L , R , x * 2 );
	if( R > mid )	res += Query( L , R , x * 2 + 1 );
	return res;
}

int main()
{
	scanf(" %lld %lld",&N,&M);
	Build(1 , N , 1);
	for(LL i = 1 ; i <= M ; i++){
		LL u , v;	scanf(" %lld %lld",&u,&v);
		Update_line(u , v , 1 , 1);
	}
	printf("%lld\n",Query(1 , N , 1));
}
/*
100 3
1 15
2 14
3 16


100 5
1 5
6 10
11 15
20 25
21 30
*/

线段树维护区间  '^':

一个长度为N的序列

单点修改某个点的值

查询一段区间区间 a[i ... j] 的区间异或和

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值