poj 2528 线段树+离散化
题目链接:http://poj.org/problem?id=2528
题意:
在墙上贴海报,输入n(1<=n<=10000),表示n张海报,后n行输入 两整数l,r ( 1<= l, r<= 1e9 ),表示海报从编号为l的石头一直贴到编号为r的石头,输入顺序即为粘贴顺序。问n张贴完之后,还能看到多少张海报。
思路:
显然区间操作,很容易联想到线段树操作,只不过区间 l,r 最大范围可达1e9,直接建树,内存必爆。 那么就需要避开1e9的数据,进行离散化,将区间变成(1到n)
至于如何离散化,原理是映射+压缩。
样例:
1 5 1 4 2 6 8 10 3 4 7 10
1 4 2 6 8 10 3 4 7 10
排序+去重 : 1 2 3 4 6 7 8 10 存入x数组
对上数组进行编号 1 2 3 4 5 6 7 8 即x【1】=1 x【2】=2 x【5】=6 x【8】=10 (即对原数组进行压缩)
本题特殊的一点:需要中间插值
设一个样例 3 1 10 1 3 5 10 进行离散化: 1 3 5 10 编号: 1 2 3 4 依次贴海报 1 10 对应的是 1 4 1 3 对应的是 1 2 5 10 3 4 显然 依次贴【1,4】 【1,2】 【3,4】 显然第一张海报【1,4】被覆盖,即答案为:2 但是实际答案为3。 至于如何解决: 中间插值 (即对两个相邻数字,相差大于1的插入某值) 进行中间插值离散化: 1 2 3 4 5 6 10 编号: 1 2 3 4 5 6 7 这时答案为3
AC代码:
#include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<cstdlib> #include<cmath> #include<queue> #include<stack> #include<map> #include<algorithm> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define Mem0(x) memset(x,0,sizeof(x)) #define Mem1(x) memset(x,-1,sizeof(x)) #define MemX(x) memset(x,0x3f,sizeof(x)) using namespace std; typedef long long ll; const int inf=0x3f3f3f; const double pi=acos(-1.0); const int MAXN=10010; struct Tree{ int l,r,lazy; }tree[MAXN<<4]; struct s{ int l,r; }a[MAXN<<4]; int x[MAXN<<4]; bool hash[MAXN<<4]; int n,ans; void pushdown(int rt) { tree[rt<<1].lazy=tree[rt<<1|1].lazy=tree[rt].lazy; tree[rt].lazy=-1; } void update(int left,int right,int c,int l,int r,int rt) { if (l>=left&&r<=right){ tree[rt].lazy=c; return ; } if (tree[rt].lazy!=-1) pushdown(rt); int mid=(l+r)>>1; if (mid>=left) update(left,right,c,l,mid,rt<<1); if (mid<right) update(left,right,c,mid+1,r,rt<<1|1); return ; } void query(int l,int r,int rt) { if (l==r){ if (!hash[tree[rt].lazy]){ ans++; hash[tree[rt].lazy]=true; } return ; } if (tree[rt].lazy!=-1) pushdown(rt); int mid=(l+r)>>1; query(l,mid,rt<<1); query(mid+1,r,rt<<1|1); } int main() { int n,t; scanf("%d",&t); while (t--){ memset(tree,-1,sizeof(tree)); memset(hash,false,sizeof(hash)); int cnt=0; scanf("%d",&n); for (int i=1;i<=n;i++){ scanf("%d%d",&a[i].l,&a[i].r); x[++cnt]=a[i].l; x[++cnt]=a[i].r; } sort(x+1,x+cnt+1); int size=unique(x+1,x+cnt+1)-x-1; //离散化+去重 for (int i=size;i>1;i--){ //中间增值 if (x[i]-x[i-1]>1) x[++size]=x[i]-1; } sort(x+1,x+size+1); for (int i=1;i<=n;i++){ int l=lower_bound(x+1,x+size+1,a[i].l)-x; //二分查找的内库函数 int r=lower_bound(x+1,x+size+1,a[i].r)-x; update(l,r,i,1,size,1); } ans=0; query(1,size,1); cout<<ans<<endl; } return 0; }