Count the Colors ZOJ - 1610 (线段树)

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610
题意:将一段[1, n]的区间,对于区间中的某些子区间染成不同的颜色,问染完色以后每种颜色的区间有几段(若为0不输出), 例如染完以后区间[1, 4]为1,[5, 6]为2, 故颜色为1的为1段, 2的为1段。

输入 :n, n个操作, 每一个操作, x, y, z 代表将[x, y]染成z颜色

解题思路:先按题意染色, 查询时用一个变量temp永远标记当前所遍历区间段的左边的颜色(temp标记的为整段区间为一个颜色的子区间的颜色, 同样查询也是对于这种区间计算),如果不同则将对应颜色的结果加一。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
#define lson ins<<1
#define rson ins<<1|1
#define merge tree[ins]=tree[lson]+tree[rson]
#define mid (r+l)/2

using namespace std;

const int Max = 200052;
int Hash[Max], ans[Max];
int temp;
struct node{
    int x, y, z;
}data[Max>>1];
struct Tree {
    int l, r;
    int sum, lazy;
    void updata(int x){
        sum=(r-l+1);
        lazy=x;
    }
} tree[Max << 2];
inline void push_up(int ins){
    if(tree[lson].sum||tree[rson].sum)tree[ins].sum=-1;
}
inline void build(int l, int r, int ins){
    tree[ins].l=l, tree[ins].r=r,tree[ins].sum=0, tree[ins].lazy=-1;//没有颜色表示为-1
    if(l<r){
        build(l, mid, lson);
        build(mid+1, r, rson);
    }
}
inline void push_down(int ins){
    int lazyval=tree[ins].lazy;
    tree[ins].lazy=-1;
    if(lazyval==-1)return;
    tree[lson].updata(lazyval);
    tree[rson].updata(lazyval);
}
inline void updata_tree(int ql, int qr, int ins, int add){
    int l=tree[ins].l, r=tree[ins].r;
    if(l>=ql&&r<=qr){
        tree[ins].updata(add);
    }
    else {
        push_down(ins);
        if(ql<=mid)updata_tree(ql, qr, lson, add);
        if(qr>mid)updata_tree(ql, qr, rson, add);
        push_up(ins);
    }
}
inline int query(int ins){
    int l=tree[ins].l,r=tree[ins].r;//由于查询永远是先查询左子树后查询右子树, 故在查询时对于整段区间为一个颜色的可以直接用temp标记,并在下一次查询到另一个同样整段区间一个颜色的区间可以直接于temp相比较,因为这样的两个区间永远时由左到右相邻的
    if(tree[ins].lazy!=-1||l==r){
        if(tree[ins].lazy!=-1&&tree[ins].lazy!=temp)
            ans[tree[ins].lazy]++;//如果不同则对应颜色的结果加一
        temp=tree[ins].lazy;
    }
    else if(tree[ins].sum){
        query(lson);
        query(rson);
    }
}
int main(){
    int n;
    while(~scanf("%d", &n)){
        int max1=0, max2=0;
        for(int a=1;a<=n; a++){
            scanf("%d%d%d", &data[a].x, &data[a].y, &data[a].z);
            max1=max(max1, data[a].y);
            max2=max(max2, data[a].z);
        }
        build(1, max1, 1);
        memset(ans, 0, sizeof(ans));
        for(int a=1;a<=n;a++){
            updata_tree(data[a].x+1, data[a].y, 1, data[a].z);
        }
        temp=-1;//初始化为没有颜色
        query(1);
        for(int a=0; a<=max2;a++){
            if(ans[a]){
                printf("%d %d\n", a, ans[a]);
            }
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值