zoj-1610线段树刷题


title: zoj-1610线段树刷题
date: 2018-10-16 16:49:47
tags:

  • acm
  • 刷题
    categories:
  • ACM-线段树

概述

这道题是一道简单的线段树区间染色问题,,,

但是,,,,刚学lazy更新没多久的我看到这样的题心里还是发怵,,,

本来是一道简单的题一开始就是不知道怎么用线段树维护染色的区间,,,还有一个老毛病,,,还是不知道怎么把题目里的信息抽象出来,,,

明确线段树所要维护的信息以及如何对这些信息如何更新和查询,,,

思路分析

  • 这道题和前几天做的那道贴海报的题很像,,,都是在一个很大的区间里进行连续的区间覆盖操作,,,

  • 然后问你最后露出来的颜色、海报有几种,,,只不过这道题是要列出每种颜色出现了几个区间,,,

  • 首先,,,这道题染色是区间之间的染色,,,就是说"1 2 1"是指在1 , 2这个长度只有1的区间里染色成颜色1,,,而那道海报的题是指1 , 2这两个块贴上海报,,,,这就意味着我们用线段树来维护染色操作时要将所给的左端点加一,,

  • 全部染色完了(更新)之后,,,就是对整个区域查询,,,然后把有颜色覆盖的区域都保存到另一个数组里,,,也就是最后染色后的区域,,,然后遍历这个区域,,,数出对应的颜色的个数就行了,,,

  • 更新时用到了lazy操作

参考

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define aaa cout<<"2333"<<endl;
const int maxn = 8005;

int col[maxn << 2];
int vis[maxn << 2];
int ans[maxn << 2];

void pushdown(int rt)
{
    if(~col[rt])
    {
        col[rt << 1] = col[rt << 1 | 1] = col[rt];
        col[rt] = -1;//父节点有多种染色标记为-1
    }
}
void update(int rt , int l , int r , int L , int R , int val)
{
    if(L <= l && r <= R)
    {
        //当该区间在所要染色的区间里时染色
        col[rt] = val;
        return;
    }
    if(col[rt] == val)  return;
    int mid = (l + r) >> 1;
    if(~col[rt])        //染过色又要染其他颜色时下推
        pushdown(rt);
    if(L <= mid)    update(lson , L , R , val);
    if(R >  mid)    update(rson , L , R , val);
    return;
}
void query(int rt , int l , int r)
{
    if(col[rt] >= 0)
    {
        //把存在的颜色保存到vis数组里
        for(int i = l; i <= r; ++i)
            vis[i] = col[rt];
        return;
    }
    if(col[rt] == -1 && l != r)
    {
        //已经保存的区间就不再查询了
        int mid = (l + r) >> 1;
        query(lson);
        query(rson);
    }
    return;
}
int main()
{
    int n;
    while(scanf("%d" , &n) != EOF)
    {
        //初始化操作,,,无需再建树
        memset(col , -1 , sizeof(col));
        memset(vis , -1 , sizeof(vis));
        memset(ans , 0 , sizeof(ans));
        int a , b , c;
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d%d" , &a , &b , &c);
            update(1 , 1 , 8000 , a + 1 , b , c);//左端点++
        }

        query(1 , 1 , 8000);

        //数出每个颜色的个数
        int i = 1;
        while(i < maxn)
        {
            int color = vis[i];
            int j = i + 1;
            if(color == -1)
            {
                ++i;
                continue;
            }
            while(~vis[j] && vis[j] == color && j < maxn)   ++j;
            ++ans[color];
            i = j;
        }

        for(int i = 0; i < maxn; ++i)
        {
            if(ans[i])  //颜色存在输出
                printf("%d %d
" , i , ans[i]);
        }
        printf("
");
    }
}

总结

  • 还是不能找不出维护的信息以及如何查询
  • 染色问题是线段树的区间覆盖问题,,,节点一般保存颜色信息
剑之所指,心之所向,身之所往!!!
原文地址:https://www.cnblogs.com/31415926535x/p/9799274.html