Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 43507 | Accepted: 12693 |
Description
Input
Output
Sample Input
1 5 1 4 2 6 8 10 3 4 7 10
Sample Output
4
Source
关于区间离散的一些知识:
通俗点说,离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:
有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。
现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9
然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9
对其升序排序,得2 3 4 6 8 9 10
然后建立映射
2 3 4 6 8 9 10
↓ ↓ ↓ ↓ ↓ ↓ ↓
1 2 3 4 5 6 7
那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。
离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。
代码:
1 /*poj 2528 线段树+离散化*/ 2 //#define LOCAL 3 #include<stdio.h> 4 #include<string.h> 5 #include<stdlib.h> 6 #include<iostream> 7 #include<algorithm> 8 9 #define MAXN 10000010 10 #define maxn 10005 11 using namespace std; 12 13 struct node 14 { 15 int st; 16 int en; 17 }ss[maxn]; 18 19 int lis[maxn<<1]; //离散化素组 20 int hash[MAXN]; //运用哈希表 21 int ans; 22 int vis[maxn]; 23 24 struct post 25 { 26 int lef,rig; 27 int mid(){ 28 return lef+((rig-lef)>>1); 29 } 30 int id; //颜色种类 31 int type; //用于延迟 32 }poster[maxn<<3]; 33 34 void build_seg(int left,int right,int pos) 35 { 36 poster[pos].lef=left; 37 poster[pos].rig=right; 38 poster[pos].id=0; 39 poster[pos].type=0; 40 if(left==right) return ; 41 int mid=poster[pos].mid(); 42 build_seg(left,mid,pos<<1); 43 build_seg(mid+1,right,pos<<1|1); 44 } 45 46 void Update(int left,int right,int pos,int id) 47 { 48 if(poster[pos].lef>=left&&poster[pos].rig<=right) 49 { 50 poster[pos].id=id; 51 poster[pos].type=id; 52 return ; 53 } 54 if(poster[pos].type&&poster[pos].lef!=poster[pos].rig) 55 { 56 //向下更新一次 57 poster[pos<<1].type=poster[pos<<1|1].type=poster[pos].type; 58 poster[pos<<1].id=poster[pos<<1|1].id=poster[pos].id; 59 poster[pos].type=0; 60 } 61 int mid=poster[pos].mid(); 62 if(mid>=left) 63 Update(left,right,pos<<1,id); 64 if(mid<right) 65 Update(left,right,pos<<1|1,id); 66 if(poster[pos].lef!=poster[pos].rig) 67 { 68 if(poster[pos<<1].id==poster[pos<<1|1].id) 69 poster[pos].id=poster[pos<<1].id; 70 else 71 poster[pos].id=0; //说明有多种可能,需要再向下查询统计 72 } 73 } 74 75 void query(int left,int right,int pos) //进行统计 76 { 77 if(poster[pos].lef<left||poster[pos].rig>right) 78 return ; 79 if(poster[pos].id) 80 { 81 if(!vis[poster[pos].id]) 82 { 83 ans++; 84 vis[poster[pos].id]=true; 85 } 86 return; 87 } 88 if(poster[pos].lef!=poster[pos].rig){ 89 query(left,right,pos<<1); 90 query(left,right,pos<<1|1); 91 } 92 } 93 94 int main() 95 { 96 #ifdef LOCAL 97 freopen("test.in","r",stdin); 98 #endif 99 int cas,n; 100 scanf("%d",&cas); 101 while(cas--) 102 { 103 scanf("%d",&n); 104 int k=0; 105 memset(hash,0,sizeof(hash)); 106 memset(vis,0,sizeof(vis)); //初始化为0表示都没有访问过 107 for(int i=0;i<n;i++) 108 { 109 scanf("%d %d",&ss[i].st,&ss[i].en); 110 lis[k++]=ss[i].st; 111 lis[k++]=ss[i].en; 112 } 113 sort(lis,lis+k); //升序 114 int j=0; 115 for(int i=0;i<k;i++) 116 { 117 if(hash[lis[i]]==0) 118 hash[lis[i]]=++j; //编号从1起 119 } 120 build_seg(1,j,1); 121 for(int i=0;i<n;i++){ 122 Update(hash[ss[i].st],hash[ss[i].en],1,i+1); 123 } 124 ans=0; 125 query(1,j,1); 126 printf("%d\n",ans); 127 } 128 return 0; 129 }