ZOJ 1610 Count the Colors

1610 Count the Colors

题目链接-1610 Count the Colors

在这里插入图片描述
Sample Input

5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1

Sample Output

1 1
2 1
3 1

1 1

0 2
1 1

题目大意

对一段区间进行涂色,0~8000长的区间,有n次染色操作,接下来每次操作表示把[l,r]区间的线段涂成k的颜色,k的范围都是0到8000(代表不同颜色的编号),每次涂色会覆盖该区间原来的颜色,问最后每一种可见的颜色共占多少个不连续的区间

解题思路

思路1

线段树+lazytag

  • 这道题是不用建树的,因为更新的时候就直接覆盖掉了,所以一个memset置为-1就行

  • 用线段树维护一段区间的颜色,区间覆盖后将叶子节点信息取出来扫一遍即可

  • 因为涂色覆盖的是区间而不是点,特殊判断连续同色的 如把2-3涂成1,3-4涂成1,查询2-4时应是一种颜色 ,所以为了解决区间线段染色问题,区间可以取左开右闭,即[a+1,b]

  • 一个节点表示一段区间,如果这段区间是纯色的,那么会在这个点上进行标记,就不需要对其子区间进行涂色了,除非下次图色的时候发生覆盖,才需要区间更新,即当出现新的线段覆盖的时候再pushdown,这样做效率更高

  • 记得加一个判断来检测此区间的右边一个节点的颜色值是否和当前区间的颜色值相同,若不同才能进行加1操作,否则将会多算一个颜色带

  • 具体操作见代码

一定不要用n来建树!!!n是染色操作次数!!!否则会segmentation fault,本蒟蒻就是因为这个问题segmentation fault了无数次, 树是固定的,在建树的时候要用8000来建树
附上代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<iomanip>
#include<cassert>
#include<climits>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<unordered_map>
#include<unordered_set>
#define lowbit(x) (x &(-x))
using namespace std;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-10;
const int M=1e9+7;
const int N=1e5+5;
typedef long long ll;
typedef pair<int,int> PII;
int col[N<<2],sum[N],ass;//ass存的是前一段的颜色
void pushdown(int i){//延迟覆盖 不然可能会TLE
	if(col[i]!=-1){
		col[i<<1]=col[i<<1|1]=col[i];
		col[i]=-1;
	}
}
void updata(int L,int R,int v,int l,int r,int i){
	if(L<=l&&r<=R){
		col[i]=v;
		return ;
	}
	pushdown(i);
	int m=l+((r-l)>>1);
	if(L<=m)
		updata(L,R,v,l,m,i<<1);
	if(m<R)
		updata(L,R,v,m+1,r,i<<1|1);
}
void query(int l,int r,int i){
	if(l==r){
		if(col[i]>=0&&col[i]!=ass)
		//不与前一个节点颜色相同且要是合理的颜色编号(否则数组越界)
			sum[col[i]]++;//记算颜色占的区间数
		ass=col[i];//更新前一个节点的颜色
		return ;
	}
	pushdown(i);
	int m=l+((r-l)>>1);
	query(l,m,i<<1);
	query(m+1,r,i<<1|1);
}
signed main(){
	
	int n;
	while(scanf("%d",&n)!=EOF){
		memset(col,-1,sizeof col);//初始化颜色为-1
		memset(sum,0,sizeof sum);//用来计数
		for(int i=0;i<n;i++){
			int x,y,v;
			scanf("%d%d%d",&x,&y,&v);
			updata(x+1,y,v,1,8000,1);
		}
		query(1,8000,1);
		for(int i=0;i<=8000;i++)
			if(sum[i])
				printf("%d %d\n",i,sum[i]);
		printf("\n");//没有这个换行会PE
	}
	return 0;
}


思路2

解题思路
由于数据范围只有8000,所以也可以直接暴力模拟

附上代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (10000+10)
#define MAXM (50000000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
using namespace std;
int num[MAXN];
int color[MAXN];
int main(){
    int n;
    while(Ri(n) != EOF){
        int Max = -INF;
        CLR(color, -1);
        for(int i = 0; i < n; i++){
            int x, y, c;
            Ri(x); Ri(y); Ri(c);
            Max = max(Max, c);
            for(int j = x; j < y; j++)
                color[j] = c;
        }
        CLR(num, 0);
        for(int i = 0; i <= 8000; ){
            int temp = color[i];
            if(temp == -1){
                i++;
                continue;
            }
            i++;
            while(temp == color[i])
                i++;
            num[temp]++;
        }
        for(int i = 0; i <= Max; i++)
            if(num[i])
                printf("%d %d\n", i, num[i]);
        printf("\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值