这道是一个线段树的题目,题意是一个区间染色,每次给你的是端点。
这道题题意是给你每次给你一个区间的端点来吧区间内部染色
- 要注意给你的是区间端点,而线段树维护的都是线段,这里就需要把端点转化为区间,那么可以把左端点的值++,原先的两个端点就看作了区间了。例如原先是0,4,是将0~4染色,变为1~4,就是把第一个区间到第四个区间染色(四个区间分别是[0,1],[1,2],[2,3],[3,4])
- 注意连续的一段只算一次,那么每次记录上次的值,看看这次统计和上次是否一致。
这道题还和上次写的题很像都是区间染色 线段树加离散化 POJ 2528 Mayor’s posters
参考代码
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
typedef pair<int,int> pii ;
const int N = 10100;
int n ;
map<int,int> m ; //使用map来统计每种颜色出现的数量
int pre = - 1 ;
struct node
{
int l,r,col;
bool flag ;
}tr[N * 4];
void init(){
pre = - 1; //pre 来记录上次出现的颜色
m.clear() ;
}
void pushdown(int u){ //如果当前区间是整个颜色都相同就把颜色传递下去
node & root = tr[u] , & left = tr[u << 1] , & right = tr[u << 1 | 1] ;
if(root.flag){
left.col = right.col = root.col ;
left.flag = right.flag = 1 ;
root.flag = 0 ;
}
}
void build(int u,int l,int r){
tr[u] = {l,r,-1,1} ; //flag置为1代表当前区间是颜色相同,col置为-1代表无颜色。
if(l != r){
int mid = l + r >> 1;
build(u << 1 ,l,mid) ,build(u << 1 | 1,mid + 1, r) ;
}
}
void modify(int u,int l,int r,int x){
if(tr[u].l >= l && tr[u].r <= r){
tr[u].col = x ;
tr[u].flag = 1;
return ;
}
pushdown(u) ;
int mid = tr[u].l + tr[u].r >> 1 ;
if(l <= mid) modify(u << 1,l ,r,x);
if(r >= mid + 1 ) modify(u << 1 | 1,l ,r,x) ;
}
void query(int u,int l,int r){
if(tr[u].l == tr[u].r || tr[u].flag){
if(tr[u].col != -1 && tr[u].col != pre){ // 如果颜色不是-1并且不与上次相同就++
m[tr[u].col] ++ ;
}
pre = tr[u].col ; //记录上次颜色
}
else{
pushdown(u) ;
int mid = tr[u].l + tr[u].r >> 1 ;
if(l <= mid ) query(u << 1 , l ,r) ;
if(r >= mid + 1 ) query(u <<1 | 1, l, r) ;
}
}
int main(){
ios::sync_with_stdio(false) ;
cin.tie(0) ;
cout.tie(0) ;
while(cin >> n){
init() ;
build(1,1,8001) ;
while(n -- ){
int a,b,c;
cin >> a >> b>> c ;
if(a > b) swap(a,b) ; //处理读入是两个端点,转化为区间
a++ ;
modify(1,a,b,c) ;
}
query(1,1,8001) ;
for(pii t : m){
cout << t.first << " " << t.second << "\n" ; // 输出答案
}
cout << "\n" ;
}
return 0;
}