ZOJ 1610 Count the Colors (线段树成段更新)

题意 : 给出 n 个染色操作,问你到最后区间上能看见的各个颜色所拥有的区间块有多少个

分析 : 使用线段树成段更新然后再暴力查询总区间的颜色信息即可,这里需要注意的是给区间染色,而不是给点染色,所以对于区间(L, R)我们只要让左端点+1即可按照正常的线段树操作来做。

#include<bits/stdc++.h>
#define lson l,   m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
const int maxn = 8000 + 5;
const int INF = 0x3f3f3f3f;
struct Query{ int L, R, val; };
int col[maxn<<2], cnt[maxn], Rmax, ColorMax;
Query Q[maxn];

inline void PutDown(int rt)
{
    if(col[rt] >= 0){
        col[rt<<1] = col[rt<<1|1] = col[rt];
        col[rt] = -1;
    }
}

inline void update(int L, int R, int val, int l, int r, int rt)
{
    if(L <= l && r <= R){
        col[rt] = val;
        return ;
    }
    PutDown(rt);
    int m = (l + r) / 2;
    if(L <= m) update(L, R, val, lson);
    if(R >  m) update(L, R, val, rson);
}

int query(int pos, int l, int r, int rt)
{
    if(l == r) return col[rt];
    PutDown(rt);
    int m = (l + r) / 2;
    int ret;
    if(pos <= m) ret = query(pos, lson);
    if(pos >  m) ret = query(pos, rson);
    return ret;
}

int main(void)
{
    int paint;
    while(~scanf("%d", &paint)){

        Rmax = ColorMax = -INF;

        for(int i=1; i<=paint; i++){
            scanf("%d %d %d", &Q[i].L, &Q[i].R, &Q[i].val);
            Q[i].L++;
            Rmax = max(Rmax, Q[i].R);///记录区间右端可以多大
            ColorMax = max(ColorMax, Q[i].val);///记录颜色的最大值
        }

        memset(col, -1, sizeof(col));
        for(int i=1; i<=paint; i++){
            if(Q[i].L-1 < Q[i].R)///说明给出的是一个点,没有覆盖掉哪一段,不用更新
                update(Q[i].L, Q[i].R, Q[i].val, 1, Rmax, 1);
        }

        memset(cnt, 0, sizeof(cnt));
        int last = -1;
        for(int i=1; i<=Rmax; i++){///查询区间内每个点的信息,用cnt[]数组来记录拥有的这些颜色占的段数
            int color = query(i, 1, Rmax, 1);
            if(color == -1) {last = -1; continue;}///注意如果没有被染色,last要赋值成-1,不能直接continue
            if(color != last){
                cnt[color]++;
            }
            last = color;
        }

        for(int i=0; i<=ColorMax; i++){
            if(cnt[i]>0){
                printf("%d %d\n", i, cnt[i]);
            }
        }
        puts("");
    }
    return 0;
}

瞎 : query操作的时候由于有lazy tag所以需要PutDown,此题虽然不难但是如果独立写一个线段树并且AC估计能够发现自身的一些问题,注意实现细节....

时间: 2024-11-06 01:49:12

ZOJ 1610 Count the Colors (线段树成段更新)的相关文章

ZOJ1610_Count the Colors(线段树/成段更新)

解题报告 题意: 一根长度8000的线段上染色,求染完之后,每个颜色在线段上有多少个间断的区间. 思路: 区间问题用线段树,成段的更新区间,最后把所有的区间下压到叶子结点,统计叶子结点的颜色. #include <iostream> #include <cstring> #include <cstdio> using namespace std; int lz[32000],_hash[10000],color[10000],cnt; void push_down(in

ZOJ 1610 Count the Colors(线段树,区间覆盖,单点查询)

Count the Colors Time Limit: 2 Seconds      Memory Limit: 65536 KB Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. Your task is counting the segments of different colors you can s

ZOJ 1610 Count the Colors(线段树,但暴力未必不行)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610 Description Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. Your task is counting the segments of different color

ZOJ - 1610 Count the Colors 线段树区间修改

Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. Your task is counting the segments of different colors you can see at last. InputThe first line of each data set contains exactly o

POJ 2777 Count Color (线段树成段更新+二进制思维)

题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的颜色有几种. 很明显的线段树成段更新,但是查询却不好弄.经过提醒,发现颜色的种类最多不超过30种,所以我们用二进制的思维解决这个问题,颜色1可以用二进制的1表示,同理,颜色2用二进制的10表示,3用100,....假设有一个区间有颜色2和颜色3,那么区间的值为二进制的110(十进制为6).那我们就把

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

POJ 2528 Mayor&#39;s posters (hash+线段树成段更新)

题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW.后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报.现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到.) 思路:简单的成段更新,但是数据量是1千万,会MT,所以要区间压缩(离散化),保证覆盖的关系不变,离散化的时候有个易错的细节,poj数据水了,这个易错点引用h

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是