ZOJ 1610 Count the Colors
题目描述:
题目链接:ZOJ 1610 Count the Colors
题目大意:
在一条长度为8000的线段上染色,每次把区间[a,b]染成c颜色。后面染上去的颜色会覆盖掉之前的颜色。如果最后该区间上存在某颜色,则输出该颜色有几段。
解题思路:
显然是对于区间的更新。不过由于该题数据比较弱,所以直接模拟暴力即可过。但是这里还是给出线段树的做法。每染一个颜色便对一个区间进行更新。最所有的输入结束后,对于整个线段树进行一个查询。查询过程中将所有的点的颜色存入一个数组。最后对这个数组遍历计算出每个颜色对应的出现次数,最后依次输出即可。
复杂度分析:
时间复杂度 :
O(logN)
空间复杂度 :
O(N)
AC代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int maxn = 8000;
int y1,y2,c,color[maxn << 2],vis[maxn << 2],ans[maxn << 2];
void pushdown(int o){
int lc = o << 1, rc = o << 1 | 1;
if(color[o] >= 0){
color[lc] = color[rc] = color[o];
color[o] = -1;
}
}
void update(int o, int L, int R){
int lc = o << 1, rc = o << 1 | 1;
if(y1 <= L && y2 >= R){
color[o] = c;
}
else{
if(color[o] == c) return;
pushdown(o);
int M = L + (R - L)/2;
if(y1 <= M) update(lc,L,M);
if(y2 > M) update(rc,M+1,R);
}
}
void query(int o, int L, int R){
if(color[o] >= 0){
for(int i = L; i <= R; i++)
vis[i] = color[o];
return;
}
if(L != R && color[o] == -1){
int M = L + (R - L)/2;
query(o*2,L,M);
query(o*2+1,M+1,R);
}
}
int main(){
int T;
while(scanf("%d",&T) != EOF){
memset(color,-1,sizeof(color));
memset(vis,-1,sizeof(vis));
memset(ans,0,sizeof(ans));
int n = T;
while(T--){
scanf("%d%d%d",&y1,&y2,&c);
y1++;
update(1,1,maxn);
}
query(1,1,maxn);
int i = 1;
while(i <= maxn){
int tmp = vis[i], j = i + 1;
if(tmp == -1){
i++;
continue;
}
while(vis[j] != -1 && vis[j] == tmp && j <= maxn) j++;
ans[tmp]++;
i = j;
}
for(int i = 0; i <= maxn; i++){
if(ans[i]) printf(("%d %d\n"),i,ans[i]);
}
printf("\n");
}
return 0;
}