小記:這題真TMD煩啊,我一個建樹出現了一點小問題,就是沒有建立起葉子節點像(1,1) (2,2)等這樣的點,導致了答案一直錯,連樣例都過不了,但是我又想不通哪裏錯了
QAQ
思路:首先hash離散化,有用線段樹做矩形交面積等題的應該會有用到的時候,離散化就是將原本離的很開的點,變成連續的點,這樣建樹就不會MLE了。
例如原本是 2 10 100 1000,離散化一下就變成
1 2 3 4
就這樣。
離散化的原因就是因爲題目的數據,一個1千萬,一個1萬,必須離散化
然後線段樹就是爲每一個海報插入線段樹,然後標記所染的色,之前有的也覆蓋掉。
線段樹節點加一個顏色標記,表示這一段是什麼顏色,
在這裏-1表示多色,0表示無色,大於0表示單色
循環的插入線段樹裏,對每一段依次染色,完成染色之後就是計算結果了
遞歸求解,如果某一段是單色那麼就看這個顏色是否被標記了,沒有被標記那麼就標記,然後答案就+1,否則就繼續往下遞歸,無色的就不要遞歸了。
代碼:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define REP(a,b,c) for(int a = b; a < c; ++a)
#define eps 10e-8
const int MAX_ = 10010;
const int N = 10000010;
const int INF = 0x7fffffff;
struct node{
int l, r;
int col;
}tree[MAX_*8];
int ans;
int a[MAX_], b[MAX_];
int x[MAX_*2];
int hash[N];
bool vis[MAX_];
void build(int l, int r, int k)
{
int mid = l + (r-l)/2;
tree[k].l = l;
tree[k].r = r;
tree[k].col = 0;
if(l == r){
return ;
}
build(l, mid, k<<1);
build(mid+1, r, (k<<1)|1);
}
void insert(int col, int l, int r, int k)
{
if(l > tree[k].r || r < tree[k].l){return ;}
if(l <= tree[k].l && r >= tree[k].r){
tree[k].col = col;
return ;
}
if(tree[k].col >= 0){
tree[k<<1].col = tree[(k<<1)|1].col = tree[k].col;
tree[k].col = -1;
}
insert(col, l, r, k<<1);
insert(col, l, r, (k<<1)|1);
}
void query(int k)
{
if(tree[k].col == 0)return ;
if(tree[k].col > 0){
if(!vis[tree[k].col]){
vis[tree[k].col] = 1;
ans++;
}
return ;
}
if(tree[k].col == -1){
query(k<<1);
query(2*k+1);
}
return;
}
int main(){
int n, m, cnt, T;
scanf("%d", &T);
while(T-- && scanf("%d", &n)){
cnt = 0;
ans = 0;
mst(vis, 0);
REP(i, 0, n){
scanf("%d%d", &a[i], &b[i]);
x[cnt++] = a[i];
x[cnt++] = b[i];
}
sort(x, x+cnt);
cnt = unique(x, x+cnt) - x;
m = 0;
REP(i, 0, cnt){
hash[x[i]] = ++m;
}
build(1, m, 1);
REP(i, 0, n){
insert(i+1, hash[a[i]], hash[b[i]], 1);
}
query(1);
printf("%d\n", ans);
}
return 0;
}