ZOJ1610_Count the Colors _线段树的树结构

来源:互联网 发布:电子琴与电钢琴 知乎 编辑:程序博客网 时间:2024/06/03 15:00

题意

往一个线段上涂色,后涂的会覆盖先前涂的颜色。问涂完后,每一种颜色能看到几段。

思路

用线段树来做。
涂色的过程就是线段树的区间修改。
计数的过程就是单点查询,用 dfs 遍历查看每一个叶子节点的颜色。
计数过程运用了线段树的树形结构的dfs序。

超级坑点

如果两段同色线段之间有一段没涂色的,那么这应该算两段。更新 pre 的时机要注意。WA了n多个小时。

题目链接

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610

AC代码

#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int maxn = 8e3 + 10;int N = 8000;int n;int x, y, z;int node[maxn << 2];int ans[maxn];int pre;void Push_down(int p){    node[p<<1] = node[p<<1|1] = node[p];    node[p] = -1;}void Add(int p, int l, int r, int x, int y, int z){    if(x <= l && r <= y)    {        node[p] = z;        return;    }    if(node[p] != -1) Push_down(p);    int mid = (l + r) >> 1;    if(x <= mid) Add(p<<1, l, mid, x, y, z);    if(y > mid) Add(p<<1|1, mid+1, r, x, y, z);}void dfs(int p, int l, int r){    if(l == r)    {        if(node[p] != -1 && node[p] != pre)            ans[node[p]] ++;        pre = node[p];//就是这里!!!        return;    }    if(node[p] != -1) Push_down(p);    int mid = (l + r) >> 1;    dfs(p<<1, l, mid);    dfs(p<<1|1, mid+1, r);}int main(){    while(scanf("%d", &n) != EOF)    {        memset(node, -1, sizeof node);        memset(ans, 0, sizeof ans);        for(int i= 1; i<= n; i++)        {            scanf("%d %d %d", &x, &y, &z);            x ++;            Add(1, 1, N, x, y, z);        }        pre = -1;        dfs(1, 1, N);        for(int i= 0; i<= N; i++)            if(ans[i] > 0) printf("%d %d\n", i, ans[i]);        printf("\n");    }    return 0;}