线段树模板总结

线段树模板总结


线段树:

实际操作:
1.求区间最值和最值的个数

2.求区间和

2.求区间第k大(值域线段树)

3.求实际区间长度(涉及区间合并)

#include <iostream>
#include <cstdio>
#include <cstring>
#define lson rt << 1,l,mid
#define rson rt << 1 | 1,mid + 1,r
#define ll long long
using namespace std;
const int maxn = 100000 + 10;
ll a[maxn];
struct node{
	ll sum,lzy;
}t[maxn << 2];
void Pushup(int rt){
	t[rt].sum = t[rt << 1].sum + t[rt << 1 | 1].sum;
}
void Pushdown(int rt,int m){
	if(t[rt].lzy){
		t[rt << 1].lzy += t[rt].lzy;
		t[rt << 1 | 1].lzy += t[rt].lzy;//!!
		t[rt << 1].sum += t[rt].lzy * (m - (m >> 1));//!!
		t[rt << 1 | 1].sum += t[rt].lzy * (m >> 1);
		t[rt].lzy = 0;
	}
}
void Build(int rt,int l,int r){
	if(l == r) {
		t[rt].sum = a[l];
		t[rt].lzy = 0;
		return;
	}
	int mid = (l + r) >> 1;
	Build(lson); Build(rson);
	Pushup(rt);	
}
void Update(int rt,int l,int r,int a,int b,ll c){
	if(a <= l && r <= b){
		t[rt].lzy += c;
		t[rt].sum += (r - l + 1) * c;//!!
		return;
	}
	int mid = (l + r) >> 1;
	Pushdown(rt,r - l + 1);
	if(a <= mid) Update(lson,a,b,c);
	if(mid < b) Update(rson,a,b,c);//!!
	Pushup(rt);
}
ll Query(int rt,int l,int r,int a,int b){
	if(a <= l && r <= b){
		return t[rt].sum;
	}
	int mid = (l + r) >> 1;
	Pushdown(rt,r - l + 1);
	ll ret = 0;
	if(a <= mid) ret += Query(lson,a,b);
	if(mid < b) ret += Query(rson,a,b);
	return ret;
}

区间合并

节点增加4个域。

lx:从区间最左边数连续空房间的数目。rx:从区间右最边数连续空房间的数目。mx:该区间中连续空房间的总数目

col:记录该区间住人的状态,1表示全住满,0表示全空,-1表示有可以住的房间。

查询

查询是否有连续空房间数目num的时候,先查询左边,当tree[v].lx >= num的时候递归左区间;

再查询中间,当tree[v2].lx +tree[v2+1].rx >= num直接返回最左边端点;

最后查询右边,当tree[v].rx>=num递归右区间。

更新

col记录该区间的状态,利用了Lazy思想,即当tree[v].col == 1或tree[v].col == 0时(房间全住满或全不住的情况),要先把这个状态传递到左右子树,并把这个区间的col置为-1。

更新区间[st,st+num-1],pushdown + pushup

(将该区间全置为空或置为满的时候,要先把区间的状态(全空或全满)传递给左右子树,然后递归,最后再把左右子树的状态更新上来,因为子树状态改变,父亲状态肯定也会改变。这个切记不要遗漏)

POJ 3667 Hotel
题意:
有n个房间,m个询问,询问的第一个数字若为1,输入一个k,表示寻找一段长度为k的连续空房间,若能找到,则输出满足条件的整段房间里,编号最小的房间的编号,并将这k间空房占满,第一个数字若为2,则输入两个数 x,y,表示将区间x~y的房间全部清空成空房间。

#include <stdio.h>  
#include <string.h>  
#include <algorithm>  
#define lson u << 1,l,mid
#define rson u << 1 | 1,mid + 1,r
using namespace std;  

const int maxn = 50000 + 5;
int n,m,tt,a,b;
struct node
{
	int ls,rs,ms,col;
}t[maxn << 2];
void pushup(int u,int m)
{
	if(t[u << 1].col == 0) 
		t[u].ls = t[u << 1].ms + t[u << 1 | 1].ls; 
	else t[u].ls = t[u << 1].ls;
	
	if(t[u << 1 | 1].col == 0) 
		t[u].rs =  t[u << 1 | 1].ms + t[u << 1].rs;
	else t[u].rs = t[u << 1 | 1].rs;
	
	t[u].ms = max(t[u << 1].ms,t[u << 1 | 1].ms);
	t[u].ms = max(t[u].ms,t[u << 1].rs + t[u << 1 | 1].ls);
	
	if(t[u].ms == m) t[u].col = 0;
	else if(t[u].ms == 0) t[u].col = 1;
	else t[u].col = -1;
}
void pushdown(int u,int m)
{
	if(t[u].col == 0)
	{
		t[u << 1].ls = t[u << 1].rs = t[u << 1].ms = m - (m >> 1);
		t[u << 1 | 1].ls = t[u << 1 | 1].rs = t[u << 1 | 1].ms = (m >> 1);
		t[u << 1].col = t[u << 1 | 1].col = 0;
	}
	else if(t[u].col == 1)
	{
		t[u << 1].ls = t[u << 1].rs = t[u << 1].ms = 0;
		t[u << 1 | 1].ls = t[u << 1 | 1].rs = t[u << 1 | 1].ms = 0;
		t[u << 1].col = t[u << 1 | 1].col = 1;
	}
}
void build(int u,int l,int r)
{
	t[u].col = -1;
	if(l == r) 
	{
		t[u].ls = t[u].rs = t[u].ms = r - l + 1;
		t[u].col = 0;return;
	}
	int mid = (l + r) >> 1;
	build(lson); build(rson);
	pushup(u,r - l + 1);
}
void update(int u,int l,int r,int a,int b,int c)
{
	if(a <= l && r <= b)
	{
		if(c == 0)	t[u].ls = t[u].rs = t[u].ms = r - l + 1;
		else	t[u].ls = t[u].rs = t[u].ms = 0;
		t[u].col = c;return;
	}
	pushdown(u,r - l + 1);
	int mid = (l + r) >> 1;
	if(a <= mid) update(lson,a,b,c); 
	if(mid < b) update(rson,a,b,c);
	pushup(u,r - l + 1);
}
int query(int u,int l,int r,int a)
{
	if(t[u].ls == a) return l;
	int mid = (l + r) >> 1;
	pushdown(u,r - l + 1);
	if(t[u << 1].ms >= a) query(lson,a);
	else if(t[u << 1].rs + t[u << 1 | 1].ls >= a) return mid - t[u << 1].rs + 1;
	else query(rson,a);
}
int main()
{
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(int i = 1; i <= m; ++i)
	{
		scanf("%d",&tt);
		if(tt == 1)
		{
			scanf("%d",&a);
			if(t[1].ms < a)
			{
				printf("0\n");
				continue;
			}
			int pos = query(1,1,n,a);
			printf("%d\n",pos);
			update(1,1,n,pos,pos + a - 1,1);
		}
		else
		{
			scanf("%d%d",&a,&b);
			update(1,1,n,a,a + b - 1,0);
		}
	}
	return 0;
}

参考:https://blog.csdn.net/DERITt/article/details/51062216

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值