这题是前年做过的题目,不过那时候比较水,看别人的解题报告写着就混过去了,于是今天又重做了一次。
这题算是比较经典的线段染色问题了,
但是我在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;
}