//线段树的建树过程主要有两种形式,一种形式是 // [1,3] // [1,2] [2,3] //另外一种形式是 // [1,3] // [1,2] [3,3] // [1,1] [2,2] //本文用的是第二种形式,因为有【1,1】这种形式的存在 #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<string.h> using namespace std; int c,n,left,right; int i,j; struct Node { int left,right; int cover; }; //存储线段树 Node tree[20005*4]; int reg[20005][2]; int dis[10000005]; int ep[20005]; int flag[10005]; //创建线段树 void build(int root,int l,int r){ tree[root].left=l; tree[root].right=r; tree[root].cover=0; if(l==r) return; int mid=(l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); } //向线段树中插入区间(a,b) void insert(int root,int a,int b,int col){ if(b<tree[root].left||a>tree[root].right) return; if(a<=tree[root].left && b>=tree[root].right){ tree[root].cover=col; return; } if(tree[root].cover>=0){ tree[root*2].cover=tree[root*2+1].cover=tree[root].cover; tree[root].cover=-1; } insert(root*2,a,b,col); insert(root*2+1,a,b,col); } void Count(int root,int l,int r){ if(tree[root].cover>=0) flag[tree[root].cover]=1; else if(r-l>=1){ Count(root*2,l,(l+r)>>1); Count(root*2+1,(l+r)>>1+1,r); } } int main(){ scanf("%d",&c); while(c--){ memset(dis,0,sizeof(dis)); memset(flag,0,sizeof(flag)); scanf("%d",&n); int p=0; for(i=1;i<=n;i++){ scanf("%d%d",®[i][0],®[i][1]); if(dis[reg[i][0]]==0){ //设置为访问过,这个过程是为了去重 dis[reg[i][0]]=1; ep[++p]=reg[i][0]; } if(dis[reg[i][1]]==0){ dis[reg[i][1]]=1; ep[++p]=reg[i][1]; } } //离散化 sort(ep+1,ep+1+p); int hash=0; for(i=1;i<=p;i++){ dis[ep[i]]=++hash; } //创建线段树 build(1,1,p); for(i=1;i<=n;i++){ insert(1,dis[reg[i][0]],dis[reg[i][1]],i); } Count(1,1,p); int res=0; for(i=0;i<=n;i++) if(flag[i]) res++; if(flag[0]) printf("%d\n",res-1); else printf("%d\n",res); } return 0; }