【ZOJ】1610 Count the Colors(线段树查找隔断的线段)

题目大意:有一条最长8000的线段,其中会被最多8000种颜色分割,问一整段是全部颜色的算1,这样每种颜色有多少段呢?

这道题目一开始的思路线段树存放的自然是每一段的情况,设定-1,假如不是-1的话,就表示该段颜色都是相同的,是-1的话,表示下面颜色可以继续分。

只是在查找的时候自己犯难了,想不到怎么去将所有颜色的次数查找出来。

看了题解,这边用的想法是这样的,通过线段树的query功能,每次对分query,直到遇到一段线段是纯色的就不再往下,并且将这段加入事先的数组当中。

最后再遍历这些数组,只要这一条线段与下一条线段的颜色不一样,并且不是相连的,那么对应颜色的次数就++。就是这么暴力,直接!!

曾经竞赛不怕变形题的我,现在只能做做模板题,稍微变形就不会,这真的是因为我做题目没有以前花时间的原因吗?无奈,大学太多事了。

AC代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAX 8008
#define ls rt<<1
#define rs ls|1
#define m (l+r)>>1
int sum[MAX << 2];
int a[MAX];
int cnt;
struct pos
{
	int l, r, c;
}p[MAX];
void ups(int rt)
{
	if (sum[rt] != -1)
	{
		sum[ls] = sum[rt];
		sum[rs] = sum[rt];
		sum[rt] = -1;
	}
}

void uprt(int rt)
{
	if (sum[ls] == sum[rs])
		sum[rt] = sum[ls];
}

void updata(int L, int R,int c, int l, int r, int rt)
{
	if (L <= l&&r <= R)
	{
		sum[rt] = c;
		return;
	}
	ups(rt);
	int mid = m;
	if (L < mid)
		updata(L, R, c, l, mid, ls);
	if (mid < R)
		updata(L, R, c, mid, r, rs);
	uprt(rt);
}

void query(int l, int r, int rt)
{
	if (sum[rt] != -1)
	{
		p[cnt].l = l;
		p[cnt].r = r;
		p[cnt++].c = sum[rt];
		return;
	}
	int mid = m;
	if (l == r - 1)return;
	query(l, mid, ls);
	query(mid, r, rs);
}
int main()
{
	int n;
	int L, R,C;
	while (~scanf("%d", &n))
	{
		memset(sum, -1, sizeof(sum));
		memset(a, 0, sizeof(a));
		cnt = 0;
		C = 0;
		int x, y, z;
		for (int i = 0; i < n; i++)
		{
			scanf("%d%d%d", &x, &y, &z);
			updata(x, y, z, 0, MAX, 1);
			C = max(C, z);
		}
		query(0, MAX, 1);
		for (int i = 0; i < cnt; i++)
		{
			if (i != cnt - 1 && p[i].r == p[i + 1].l&&p[i].c == p[i + 1].c)
				continue;
			a[p[i].c]++; 
		}
		for (int i = 0; i <=C;i++)
		if (a[i])
			printf("%d %d\n", i, a[i]);
		cout << endl;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值