1 /* 2 poj 2528 Mayor's posters 3 线段树 + 离散化 4 5 离散化的理解: 6 给你一系列的正整数, 例如 1, 4 , 100, 1000000000, 如果利用线段树求解的话,很明显 7 会导致内存的耗尽。所以我们做一个映射关系,将范围很大的数据映射到范围很小的数据上 8 1---->1 4----->2 100----->3 1000000000----->4 9 这样就会减少内存一些不必要的消耗 10 建立好映射关系了,接着就是利用线段树求解 11 */ 12 #include<iostream> 13 #include<cstdio> 14 #include<queue> 15 #include<cstring> 16 #include<algorithm> 17 #define N 10000010 18 #define M 10005 19 using namespace std; 20 class EDGE{ 21 public: 22 int ld, rd; 23 }; 24 int tree[M*16];//一共有M*2个端点,一个线段映射到四个点,左右端点, 左端点-1, 右端点+1, 数组的大小是线段树最底层数据个数的4倍 25 EDGE edge[M]; 26 int p[M*4]; 27 int hash[N]; 28 int n; 29 30 int insert(int p, int lr, int rr, int ld, int rd){ 31 32 if(tree[p] && lr<=ld && rd<=rr)//如果当前的区间[ld, rd]被包含在[lr, rr]中,而且[lr, rr]的区间已经被覆盖 33 return 1; 34 else if(lr==ld && rr==rd){ 35 tree[p]=1; 36 return 0; 37 } 38 else{ 39 int mid=(lr+rr)>>1; 40 int f1, f2, f3, f4; 41 if(mid>=rd) 42 f1=insert(p<<1, lr, mid, ld, rd); 43 else if(mid<ld) 44 f2=insert(p<<1|1, mid+1, rr, ld, rd); 45 else{ 46 f3=insert(p<<1, lr, mid, ld, mid); 47 f4=insert(p<<1|1, mid+1, rr, mid+1, rd); 48 } 49 tree[p]=tree[p<<1] && tree[p<<1|1];//两个子树都被覆盖的时候父类才会被覆盖 50 if(mid>=rd) 51 return f1; 52 else if(mid<ld) 53 return f2; 54 else return f3 && f4; 55 } 56 } 57 /* 58 3 59 1 10 60 1 3 61 6 10 62 如果将一个线段离散化成两个点,输出地结果是2 63 如果是四个节点,输出的结果就是3 64 而正确的结果就是3 65 */ 66 67 int main(){ 68 int t, i, nm; 69 scanf("%d", &t); 70 while(t--){ 71 int maxR=0; 72 scanf("%d", &n); 73 for(i=0; i<n; ++i){ 74 scanf("%d%d", &edge[i].ld, &edge[i].rd); 75 p[maxR++]=edge[i].ld-1; 76 p[maxR++]=edge[i].ld; 77 p[maxR++]=edge[i].rd; 78 p[maxR++]=edge[i].rd+1; 79 } 80 sort(p, p+maxR); 81 maxR=unique(p, p+maxR)-p;//元素去重 82 for(i=0, nm=0; i<maxR; ++i){ 83 hash[p[i]]=++nm; 84 } 85 memset(tree, 0, sizeof(tree));//初始值是所有的点都没有被覆盖 86 int ans=0; 87 for(i=n-1; i>=0; --i){//由外向里看真是个不错的主意 88 if(!insert(1, 1, nm, hash[edge[i].ld], hash[edge[i].rd])) 89 ++ans; 90 } 91 printf("%d\n", ans); 92 } 93 return 0; 94 }