ZOJ 1610 Count the Colors(线段树)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=610

解题思路:


这是第一次写题解写的

思路跟我之前写的POJ 2528差不多。

https://blog.csdn.net/weixin_43768644/article/details/89341259

区别是这题是要输出所有看得见的颜色,以及对应这种颜色有几段。

按顺序讲一下代码。

PART 1:

主函数中:找到建树的右界,以及初始化,build()将区间所有点染为8002

int MAXN = 1;
for (int i = 1;i<=n;i++){
    scanf("%d %d %d",x+i,y+i,c+i);
    x[i]++,c[i]++;
    MAXN  = max(MAXN,y[i]);
}
///init
build(1,1,MAXN);
//memset(tree,0,sizeof tree);
for (int i=0;i<=8000;i++) ans[i] = sum[i] = 0;

for (int i = 1;i<=n;i++){
    if (x[i]<=y[i]) update(x[i],y[i],c[i],1,1,MAXN);
}

主函数外:

对于每次给出区间进行更新,初始都染色为8002

这样给出 2

               1 3 1

               6 8 1

这样的数据就没有问题了,之前我初始化为0应该就是一直wa在这个地方 。看一下我那个poj2528题解应该就能体会到了。 维护的是一段区间内存在的颜色,如果一段区间是一种颜色中间却断了很多段,按照之前的思路,统计出的答案会是1,显然错误。这里把初始化的无色当做一种颜色,就没问题了。

#define mid int m = l+r>>1
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]
void push_up(int rt)
{
    if (tl==-1||tr==-1) tree[rt] = -1;
    else if (tl!=tr) tree[rt] = -1;
}

void update(int L,int R,int c,int rt,int l,int r)
{
    if (L<=l && r<=R){
        tree[rt] = c;
        return ;
    }
    if (tree[rt] > 0) tl = tr = tree[rt];
    mid;
    if (L<=m) update(L,R,c,lson);
    if (R>m)  update(L,R,c,rson);
    push_up(rt);
}

PART 2:

dfs遍历树得到答案,用了差分标记

void dfs(int rt,int l,int r)
{
    if (tree[rt] > 0){
        sum[l] += tree[rt];
        sum[r+1] -= tree[rt];
        return ;
    }
    if (tree[rt] == -1){
        mid;
        dfs(lson);
        dfs(rson);
    }
}

主函数中:

dfs(1,1,MAXN);

for (int i=2;i<=MAXN;i++) sum[i] += sum[i-1];

int pre = 0;
for (int i=1;i<=MAXN;i++){
    if (sum[i]!=pre){
        ans[sum[i]-1]++;
        pre = sum[i];
    }
}

完整代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#define mid int m = l+r>>1
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]

using namespace std;

const int N = 8000+5;

int tree[N<<2],sum[N],ans[N];
int x[N],y[N],c[N];

void push_up(int rt)
{
    if (tl==-1||tr==-1) tree[rt] = -1;
    else if (tl!=tr) tree[rt] = -1;
}

void update(int L,int R,int c,int rt,int l,int r)
{
    if (L<=l && r<=R){
        tree[rt] = c;
        return ;
    }
    if (tree[rt] > 0) tl = tr = tree[rt];
    mid;
    if (L<=m) update(L,R,c,lson);
    if (R>m)  update(L,R,c,rson);
    push_up(rt);
}

void build(int rt,int l,int r)
{
    if (l==r){
        tree[rt] = 8002;
        return ;
    }
    mid;
    build(lson);
    build(rson);
    push_up(rt);
}

void dfs(int rt,int l,int r)
{
    if (tree[rt] > 0){
        sum[l] += tree[rt];
        sum[r+1] -= tree[rt];
        return ;
    }
    if (tree[rt] == -1){
        mid;
        dfs(lson);
        dfs(rson);
    }
}

int main()
{
    int n;
    while (~scanf("%d",&n)){
        int MAXN = 1;
        for (int i = 1;i<=n;i++){
            scanf("%d %d %d",x+i,y+i,c+i);
            x[i]++,c[i]++;
            MAXN  = max(MAXN,y[i]);
        }
        ///init
        build(1,1,MAXN);
        //memset(tree,0,sizeof tree);
        for (int i=0;i<=8000;i++) ans[i] = sum[i] = 0;

        for (int i = 1;i<=n;i++){
            if (x[i]<=y[i]) update(x[i],y[i],c[i],1,1,MAXN);
        }
        dfs(1,1,MAXN);

        for (int i=2;i<=MAXN;i++) sum[i] += sum[i-1];

        int pre = 0;
        for (int i=1;i<=MAXN;i++){
            if (sum[i]!=pre){
                ans[sum[i]-1]++;
                pre = sum[i];
            }
        }

        for (int i=0;i<=8000;i++)
            if (ans[i]) printf("%d %d\n",i,ans[i]);
        printf("\n");
    }
    return 0;
}

第二次写:

解题思路:

区间染色覆盖的问题,同时注意0也是一种颜色,初始化的状态应该为“无颜色状态”,为了方便涂颜色,每种颜色加一,最后减一就好了。

区间颜色覆盖,最后一次询问标记每个块的颜色。

然后进行统计。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]

using namespace std;

const int N = 8e3+5;

int tree[N<<2];
int col[N],ans[N];

void push_down(int rt)
{
    tl = tr = tree[rt];
}

void push_up(int rt)
{
    if (tl==tr) tree[rt] = tl;
    else tree[rt] = -1;
}

void update(int L,int R,int x,int rt,int l,int r)
{
    if (L<=l && r<=R){
        tree[rt] = x;
        return ;
    }
    if (tree[rt]>=0) push_down(rt);
    mid;
    if (L<=m) update(L,R,x,lson);
    if (R>m)  update(L,R,x,rson);
    push_up(rt);
}

void query(int rt,int l,int r)
{
    if (tree[rt]>=0){
        for (int i=l;i<=r;i++) col[i] = tree[rt];
        return ;
    }
    mid;
    query(lson);
    query(rson);
}

void init(int rt,int l,int r)
{
    if (l==r){
        tree[rt] = 0;
        return ;
    }
    mid;
    init(lson);
    init(rson);
    push_up(rt);
}

int main()
{
    int t,n,q,x,y,v;
    while (~scanf("%d",&n)){
        init(1,1,8000);
        memset(ans,0,sizeof ans);
        while (n--){
            scanf("%d %d %d",&x,&y,&v);
            x++;v++;
            update(x,y,v,1,1,8000);
        }
        query(1,1,8000);
        for (int i=1;i<=8001;i++){
            //printf("col[%d]=%d\n",i,col[i]);
            if (col[i]!=col[i-1]) ans[col[i]]++;
        }
        for (int i=1;i<=8001;i++) if (ans[i]) printf("%d %d\n",i-1,ans[i]);
        printf("\n");
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值