线段树练习

线段树练习

概述

线段树主要操作为建树、pushUp、pushDown、单点修改、区间修改、区间查找,其中区间修改出于效率考虑涉及lazy tag,当某一区间包含在修改区间中时,直接出栈,并用一个数组保存这次修改;在下一次区间修改或区间查询时遇到有lazy tag的节点都需要将lazy tag往下pushDown一层,这样可以继续进行之前没有完成的修改,保证接下来的修改或查找正确;容易想到,一个有lazy tag的节点管理的区间必定包含其子节点的区间,其子节点区间被搜索前必定经过该节点,这能够保证lazy tag能够在合适的时刻往下pushDown

POJ2828

由于前面来的人会有被插队的可能,因此从前往后处理排队的人会使得已经在数组中的人位置不断变化,增加计算量;可考虑从后往前处理:此时这人只要一入数组,就不可能会被插队,也就是说位置不会再变;

使用权值线段树解决:定义que为最后的队列,blank为该节点剩余空位;

考虑这么一种情况:最后一个人插到位置1,此时剩下位置2、3、4,倒数第二人想要插入到位置2,但其实这个位置是相对于早于他之前来的人而非相对于这最后一人,而节点2维护的位置区间只剩下一个位置留给前面的人,因此倒数第二人只能考虑节点3维护的位置区间,他要排在这个区间的2-1=1的位置
在这里插入图片描述

AC Code

// #include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
using namespace std;

const int maxn = 200005;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define lson l, mid, ls
#define rson mid+1, r, rs

int blank[maxn<<2], que[maxn<<2], pos[maxn], v[maxn];

void pushUp(int rt) {
    blank[rt] = blank[ls] + blank[rs];
}

void build(int l, int r, int rt) {
    if(l==r) {
        blank[rt] = 1;
        return;
    }
    build(lson);
    build(rson);
    pushUp(rt);
}

void jump(int l, int r, int rt, int p, int val) {
    if(l==r) {
        blank[rt] = 0;
        que[l] = val;
        return;
    }
    if(blank[ls] >= p) jump(lson, p, val);
    else jump(rson, p-blank[ls], val);
    pushUp(rt);
}

int main() {
    int N;
    while(scanf("%d", &N)!=EOF) {
        for(int i=1; i<=N; ++i) {
            scanf("%d%d", &pos[i], &v[i]);
        }
        build(1, N, 1);
        for(int i=N; i>0; --i) {
            jump(1, N, 1, pos[i]+1, v[i]);
        }
        for(int i=1; i<=N; ++i) {
            printf("%d ", que[i]);
        }
        printf("\n");
    }
    return 0;
}

POJ1151

使用垂直于x轴的扫描线从左到右扫描所有边,其中矩形的左边为入边(增加覆盖区域)、右边为出边(减少覆盖区域),使用线段树维护覆盖区域长度,线段长度是一个连续变量,可根据y轴坐标从小到大排列使其离散化,最小单位为相邻两个y轴坐标的差;每条入边或出边覆盖的最小单位为多个,因此为区间修改,但由于每次修改后立马进行查询且查询的是整个y轴被覆盖的区域长度(也就是根节点维护的区域),lazy tag将无法减少计算量;

定义y为所有y轴坐标;segment为相邻y轴坐标的差;Line为所有入边或出边,其成员type为出边(+1)或入边(-1),成员x为x轴坐标,成员y1、y2分别上端点和下端点;node为所有节点,其成员len为维护的实际长度,成员ori_len为如果整个线段都覆盖时的长度,成员cover为该区域覆盖被覆盖次数;y2id为y轴坐标映射到排序后的y对应的index,便于后面进行边扫描时修改区域的查询

根据上述分析可知需进行两次排序:y从小到大排列、Line根据成员x从小到大排序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值