poj2528线段树解题报告,离散化+线段树
Posted 远搏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj2528线段树解题报告,离散化+线段树相关的知识,希望对你有一定的参考价值。
题目网址:http://poj.org/problem?id=2528
题意:
n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。
求出最后还能看见多少张海报。
输入:
1 5 1 4 2 6 8 10 3 4 7 10
这题用常规思路解题必定TLE,l,r太大;
通俗点说,离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:
有一条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 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <string.h> 5 using namespace std; 6 #define N 10100 7 #define M 10000000 8 bool vis[2*N];//标记出现过得海报 9 int x[2*N]; 10 struct T 11 { 12 int node,add,l,r; 13 }tree[M*4]; 14 void creat(int l,int r,int k)//建树 15 { 16 tree[k].node=0; 17 tree[k].l=l; 18 tree[k].r=r; 19 tree[k].add=0; 20 if(l==r) 21 return; 22 int mid=(l+r)>>1; 23 creat(l,mid,k<<1); 24 creat(mid+1,r,k<<1|1); 25 } 26 void pushdown(int k,int color)//延迟标记 27 { 28 int x=k<<1; 29 tree[x].add=1; 30 tree[x+1].add=1; 31 tree[x].node=color; 32 tree[x+1].node=color; 33 tree[k].add=0; 34 tree[k].node=0; 35 } 36 void Search(int l,int r,int color,int k)//更新线段树 37 { 38 if(r<tree[k].l||l>tree[k].r) 39 return ; 40 if(l<=tree[k].l&&r>=tree[k].r) 41 { 42 tree[k].node=color; 43 tree[k].add=1; 44 return ; 45 } 46 if(tree[k].add) 47 pushdown(k,tree[k].node); 48 int mid=(tree[k].l+tree[k].r)>>1; 49 if(r<=mid) 50 Search(l,r,color,k<<1); 51 else if(l>mid) 52 Search(l,r,color,k<<1|1); 53 else 54 { 55 Search(l,mid,color,k<<1); 56 Search(mid+1,r,color,k<<1|1); 57 } 58 } 59 int ans; 60 void q(int l,int r,int k)//查找不同颜色的区域 61 { 62 if(tree[k].add) 63 { 64 if(!vis[tree[k].node]) 65 { 66 ans++; 67 vis[tree[k].node]=1; 68 } 69 return ; 70 } 71 int mid=(l+r)>>1; 72 q(l,mid,k<<1); 73 q(mid+1,r,k<<1|1); 74 } 75 int s(int l,int r,int k)//二分查找 76 { 77 int mid; 78 while(l<=r) 79 { 80 mid=(l+r)>>1; 81 if(k<x[mid]) r=mid-1; 82 else if(k>x[mid]) l=mid+1; 83 else return mid; 84 } 85 return -1; 86 } 87 int main() 88 { 89 int t,n,i,j; 90 int l[N],r[N]; 91 scanf("%d",&t); 92 while(t--) 93 { 94 j=0; 95 memset(vis,0,sizeof(vis)); 96 scanf("%d",&n); 97 for(i=0;i<n;i++) 98 { 99 scanf("%d%d",&l[i],&r[i]); 100 x[j++]=l[i]; 101 x[j++]=r[i]; 102 } 103 sort(x,x+j); 104 int m=1; 105 for(i=0;i<j-1;i++) 106 { 107 if(x[i]==x[i+1]) 108 { 109 m--; 110 } 111 else 112 { 113 x[i+m]=x[i+1]; 114 } 115 } 116 j=j+m-1; 117 sort (x,x+j); 118 /*for(i=0;i<n;i++) 119 { 120 printf("%d %d ",s(0,j-1,l[i])+1,s(0,j-1,r[i])+1); 121 cout<<endl; 122 }*/ 123 creat(1,j,1); 124 for(i=0;i<n;i++) 125 { 126 Search(s(0,j-1,l[i])+1,s(0,j-1,r[i])+1,i+1,1); 127 } 128 ans=0; 129 q(1,j,1); 130 printf("%d\n",ans); 131 } 132 return 0; 133 }
以上是关于poj2528线段树解题报告,离散化+线段树的主要内容,如果未能解决你的问题,请参考以下文章
POJ训练计划2528_Mayor's posters(线段树/成段更新+离散化)
poj 2528 Mayor’s posters 离散化+线段树