1 /* 2 poj2528 3 线段树 好题,用到了离散化,二分定位,特殊的区间查寻方式;在下面的代码注释中有详细的解释; 4 */ 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 10 using namespace std; 11 typedef struct 12 { 13 int l,r; 14 int cnt;//记录该段有几张海报; 15 int num;//记录该段下面是哪一张海报,0表示没有还海报或海报不唯一; 16 }Node; 17 int a[400010][2],n,dot[400010]={0},cou[400010]={0}; 18 Node tr[800010]; 19 void build(int rt,int l,int r) 20 { 21 tr[rt].l=l; 22 tr[rt].r=r; 23 tr[rt].cnt=0; 24 tr[rt].num=0; 25 if(l==r) 26 return ; 27 int mid=(l+r)/2; 28 build(rt<<1,l,mid); 29 build((rt<<1)|1,mid+1,r); 30 } 31 void Pushdown(int rt) 32 { 33 tr[rt<<1].cnt=1; 34 tr[rt<<1|1].cnt=1; 35 tr[rt<<1].num=tr[rt].num; 36 tr[rt<<1|1].num=tr[rt].num; 37 tr[rt].cnt=2; 38 tr[rt].num=0; 39 } 40 void Update(int rt,int l,int r,int x) 41 { 42 if(tr[rt].l==l&&tr[rt].r==r) 43 { 44 tr[rt].cnt=1; 45 tr[rt].num=x; 46 return; 47 } 48 if(tr[rt].cnt==1)//当只有一张海报在这个区间的时候才需要pushdown所以可以判断一下;也可以写在pushdown函数里面,我觉得写在外面比较块; 49 Pushdown(rt); 50 if(l<=tr[rt<<1].r) 51 { 52 if(r<=tr[rt<<1].r) 53 Update(rt<<1,l,r,x); 54 else 55 Update(rt<<1,l,tr[rt<<1].r,x); 56 } 57 if(r>=tr[rt<<1|1].l) 58 { 59 if(l>=tr[rt<<1|1].l) 60 Update(rt<<1|1,l,r,x); 61 else 62 Update(rt<<1|1,tr[rt<<1|1].l,r,x); 63 } 64 if(tr[rt<<1].num==tr[rt<<1|1].num&&tr[rt<<1].cnt==1&&tr[rt<<1|1].cnt==1)//这以下是pushup的操作,写在这里了; 65 { 66 tr[rt].cnt=1; 67 tr[rt].num=tr[rt<<1].num; 68 } 69 else 70 tr[rt].cnt=2; 71 } 72 /* 73 查询操作比较有趣,因为是查寻区间的海报种类,一个海报可能是首尾可见而中间不可见,所以没办法直接查得, 74 所以在树的结点上记录的是海报的编号,这样就可以用一个辅助的数组记录哪一个在此次查询中出现过;、 75 所以每次查询要全区间查询,然后再扫一遍数组; 76 、每次扫到区间内容一质的时候就不用再扫了; 77 */ 78 void Query(int rt) 79 { 80 if(tr[rt].cnt==1) 81 { 82 cou[tr[rt].num]=1; 83 return ; 84 } 85 if(tr[rt].l==tr[rt].r) 86 return ; 87 if(tr[rt].cnt==0) 88 return ; 89 Query(rt<<1); 90 Query(rt<<1|1); 91 } 92 int Erfen(int l,int r,int x)//用来确定该点在线段上的位置(离散后的位置); 93 { 94 while(l<=r) 95 { 96 int mid=(l+r)/2; 97 if(x<dot[mid]) 98 r=mid-1; 99 else 100 l=mid+1; 101 } 102 return r; 103 } 104 int main() 105 { 106 int T; 107 scanf("%d",&T); 108 while(T--) 109 { 110 memset(dot,0,sizeof(dot)); 111 scanf("%d",&n); 112 int z=0; 113 for(int i=0;i<n;i++) 114 { 115 scanf("%d%d",&a[i][0],&a[i][1]); 116 dot[z++]=a[i][0]; 117 dot[z++]=a[i][1]; 118 } 119 sort(dot,dot+z);//将输入的数据排序后是离散化;因为数据范围比较大,因为只和区间有关,与区间内部的点没有关系,所以只要区间首尾就好; 120 int t=1; 121 for(int i=1;i<z;i++) 122 { 123 if(dot[i]!=dot[i-1]) 124 dot[t++]=dot[i]; 125 } 126 for(int i=t-1;i>0;i--) 127 { 128 if(dot[i]-dot[i-1]>1) 129 dot[t++]=dot[i-1]+1; 130 } 131 sort(dot,dot+t); 132 for(int i=t;i>0;i--) 133 dot[i]=dot[i-1]; 134 memset(tr,0,sizeof(tr)); 135 build(1,1,t+5); 136 for(int i=1;i<=n;i++) 137 { 138 int temp1=Erfen(1,t,a[i-1][0]); 139 int temp2=Erfen(1,t,a[i-1][1]); 140 Update(1,temp1,temp2,i); 141 } 142 memset(cou,0,sizeof(cou)); 143 Query(1); 144 int ans=0; 145 for(int i=1;i<=n;i++) 146 if(cou[i]==1) 147 ans++; 148 printf("%d ",ans); 149 } 150 return 0; 151 }