线段树讲解

线段树详解

本节内容待补充

线段树区间更新+离散化

同样的题目类型可参见POJ-2528
题目描述

数轴上的游戏
Description
n 个人依次(有先后顺序)在数轴上进行标记,每个人可以选取数轴上的一组连续的离散点,从而获得这些点对应的分数,每个点对应 1 分(即每个人选取左右两个端点,从而获取两个端点之间所有点对应的分数),如果有多个人选择了重复的区间,则最后进行标记的人拥有该区间,前面进行选择的人的对应区间的积分被清零。假设每个人选择的区间是随机的,问最后有多少人的积分不为0.
Input
输入的第一行为一个正整数 n∈[1,10000], 表示所有参与的人数,接下来 n 组正整数x,y∈[1,10^7], x≤y,分别表示每个人选取的左端点和右端点,每组数出现的先后顺序即为每个人进行选择的顺序。
Output
输出积分不为 0 的人的个数。

注意的点:
1、在离散化时,注意在相差值大于1的两个数中,插入一个数,避免离散化后的区间被当成点覆盖
2、内存空间可以开大一点,不然会RE

AC代码

#include
#include
#include
#include
using namespace std;

const int N = 1e5 + 10;
int n;
int num[4 * N], idx;

typedef struct
{
    int left, right;
    int priority;
}Edge;

map num_index;
Edge edge[N];
int length;

int tree[4 * N], vis[4 * N];

void print_tree()
{
    for(int i = 0; i < 10; i++)
        printf("node:%d tree:%d\n", i, tree[i]);
}

void dele_repeat()
{
    for(int i = 1; i < n * 2; i++)
        if(num[i] != num[length])
        {
            length++;
            num[length] = num[i];
        }
}

void insert_value() //在相邻的数值大于1时,插入一个值,防止区间缩小后变为点覆盖,
{
    for(int i = length; i >= 0; i--)
    {
        if(num[i] - num[i - 1] > 1) num[++length] = num[i] - 1;
    }
}

void push_down(int node)
{
    tree[node * 2 + 1] = tree[node * 2 + 2] = tree[node];
    tree[node] = -1;
}

void update_tree(int node, int start, int en, int left, int right, int priority)
{

    if(start <= left && en >= right)
    {
        tree[node] = priority;
        return;
    }
    // =-1 表示此区间并不是一个priority, != -1 表示此区间为一个priority,此时更新区间
    if(tree[node] != -1) push_down(node);

    int mid = (left + right) / 2;
    int left_node = 2 * node + 1;
    int right_node = 2 * node + 2;

    if(mid >= en) update_tree(left_node, start, en, left, mid, priority);
    else if(mid < start) update_tree(right_node, start, en, mid + 1, right, priority);
    else // 当更新区间在mid的左右区间时
    {
        update_tree(left_node, start, mid, left, mid, priority);
        update_tree(right_node, mid + 1, en, mid + 1, right, priority);
    }
}

int ans;
void query_tree(int left, int right, int node)
{
    if(!vis[tree[node]] && tree[node] != -1)
    {
        ans++;
        vis[tree[node]] = 1;
        return;
    }
    if(left == right) return;
    if(tree[node] != -1) push_down(node);

    int mid = (left + right) / 2;
    int left_node = 2 * node + 1;
    int right_node = 2 * node + 2;

    query_tree(left, mid, left_node);
    query_tree(mid + 1, right, right_node);
}

int main()
{
    memset(tree, -1, sizeof(tree));
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        cin >> edge[i].left >> edge[i].right;
        edge[i].priority = i;
        num_index[edge[i].left] = edge[i].left;
        num_index[edge[i].right] = edge[i].right;
        num[idx++] = edge[i].left;
        num[idx++] = edge[i].right;
    }
    sort(num, num + idx);

    dele_repeat();
    insert_value();
    sort(num, num + length + 1);
	// 映射index
    for(int i = 0; i <= length; i++)
        num_index[num[i]] = i;

    // 更新结点index
    for(int i = 0; i < n; i++)
    {
        edge[i].left = num_index[edge[i].left];
        edge[i].right = num_index[edge[i].right];
        update_tree(0, edge[i].left, edge[i].right, 0, length, edge[i].priority);// 更新线段树
    }
    query_tree(0, length, 0);
    printf("%d\n", ans);
  
    return 0;
}

你可能感兴趣的:(树,算法,数据结构,c语言)