~~~~
一直MLE,才发现要写离散化操作。其他就是线段树的成段更新(每次用不同标记去更新区间),最后统计下有多少种标记就OK了。
题目链接:http://poj.org/problem?id=2528
大牛写的很详细,请戳:http://blog.youkuaiyun.com/metalseed/article/details/8041334
~~~~
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 11111
#define lson rt<<1,s,m
#define rson rt<<1|1,m+1,e
using namespace std;
int x[N<<2]; //因为有离散化操作,注意数组大小,否则会RE。
int ans[N<<2];
int s[N],e[N];
int tre[N<<4];
void pushdown(int rt,int m)
{
if(tre[rt])
{
tre[rt<<1]=tre[rt<<1|1]=tre[rt];
tre[rt]=0;
}
}
void update(int l,int r,int val,int rt,int s,int e)
{
if(l<=s && r>=e)
{
tre[rt] = val;
return ;
}
pushdown(rt,e-s+1);
int m=(s+e)>>1;
if(r<=m) update(l,r,val,lson);
else if(l>m) update(l,r,val,rson);
else
{
update(l,m,val,lson);
update(m+1,r,val,rson);
}
}
int query(int pos,int rt,int s,int e)
{
if(s==e)
return tre[rt];
pushdown(rt,e-s+1);
int m=(s+e)>>1;
if(pos<=m) query(pos,lson);
else query(pos,rson);
}
int bin(int key,int ma)
{
int l=0,r=ma,m=0;
while(l<=r)
{
m=(l+r)>>1;
if(x[m]==key) return m;
else if(x[m]>key) r=m-1;
else l=m+1;
}
//return -1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int m;
scanf("%d",&m);
int n=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&s[i],&e[i]);
x[n++]=s[i];
x[n++]=e[i];
}
int cnt=1;
sort(x,x+n);
//删去重复的元素,
for(int i=1;i<n;i++)
if(x[i]!=x[i-1]) x[cnt++]=x[i];
//离散化技巧:凸显间隔(否则可能会有问题)。
for(int i=cnt-1;i>0;i--)
if(x[i]!=x[i-1]+1) x[cnt++]=x[i-1]+1;
//再一次排序,便于后面二分离散化。
sort(x,x+cnt);
memset(tre,0,sizeof(tre)); //相当于建树过程
for(int i=1;i<=m;i++)
{
int l=bin(s[i],cnt-1);
int r=bin(e[i],cnt-1);
update(l,r,i,1,0,cnt-1); //依次标记
}
int q=0;
for(int i=0;i<cnt;i++)
{
int k=query(i,1,0,cnt-1);
if(k) ans[q++]=k; //~~
}
sort(ans,ans+q);
int tot=1;
for(int i=1;i<q;i++)
if(ans[i]!=ans[i-1]) tot++;
printf("%d\n",tot);
}
return 0;
}