线段树模板总结
线段树:
实际操作:
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.youkuaiyun.com/DERITt/article/details/51062216