這題是前年做過的題目,不過那時候比較水,看別人的解題報告寫着就混過去了,於是今天又重做了一次。
這題算是比較經典的線段染色問題了,
但是我在POJ上很多人數據有問題,或者說無限WA,我總結了一下,舉一個簡單的數據
3
1 10
6 10
1 3
大家很多人離散化就變成
1 3 6 10
1 2 3 4
於是先覆蓋了
1 4
3 4
1 2
答案爲2,其實爲3
爲什麼 因爲正常的沒離散化的相鄰兩個數就是相鄰的,離散化後,相鄰的兩個數其實可能相差很大。
所以應該把線段樹寫成線段的形勢
即葉子節點爲 0 - 1 替代 常用的 1- 1 而表示 1
於是上面的數據則變成了這樣
0 10
0 3 3 10
3 5 5 10
這樣覆蓋後就能得到正確的答案3了。
詳見代碼。
#include<cstdio>
#include<algorithm>
#include<cstring>
const int maxn = 10009;
int color[maxn<<3];
int a[maxn<<1];
int b[maxn<<1];
bool vi[maxn];
void pushdown(int rt){
if(color[rt]>0){
color[rt<<1]=color[rt<<1|1]=color[rt];
}
color[rt]=-1;
}
void update(int rt,int l,int r,int L,int R,int c){
if(b[l]>=L&&b[r]<=R){
color[rt] = c;
return;
}
pushdown(rt);
int mid = (l+r)>>1;
if(b[mid]>L)update(rt<<1,l,mid,L,R,c);
if(b[mid]<R) update(rt<<1|1,mid,r,L,R,c);
}
int dfs(int rt){
int ans = 0;
// printf("%d\n",color[rt]);
if(color[rt]>0 && !vi[color[rt]]){
vi[color[rt]] = true;
ans++;
}else if(color[rt]==-1){
ans+=dfs(rt<<1);
ans+=dfs(rt<<1|1);
}
color[rt] = 0;
return ans;
}
int main(){
int _case,l,r;scanf("%d", &_case);
while(_case--){
int n;scanf("%d", &n);
for(int i=0;i<n;i++){
scanf("%d%d",&l,&r);
b[2*i]=a[2*i]=l-1;
b[2*i+1]=a[2*i+1]=r;
}
std::sort(b,b+2*n);
int num = std::unique(b,b+2*n)-b;
num--;
// printf("num:%d \n",num);
for(int i=0;i<n;i++){
update(1,0,num,a[2*i],a[2*i+1],i+1);
}
// for(int i=1;i<=n;i++) printf("%d %d\n",i,vi[i]);
printf("%d\n",dfs(1));
memset(vi, false, sizeof(vi));
}
return 0;
}