poj2528 (线段树+离散化)
传送门::http://poj.org/problem?id=2528
题意: 在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
数据:1 <= i <= n, 1 <= li <= ri <= 10000000;1 <= n <= 10000
思路:离散化+线段树
离散化 定义::把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。(by百度百科)
通俗点说就是 在不改变数据的可用性质下缩小其范围,一般只关注他们的相对大小
但对于本题而言普通离散化不行,我们还要维护一个性质,那就是是否相邻,举个例子就会明白
[1,5] [1,2] [4,5]离散后[1,4] [1,2][3,4]这样做的答案为2(原因就是二三区间归为一起,导致覆盖第一区间),而实际上答案为3
那我们应该在差值大于1的两个数之间插入一个数,避免相邻的归为一个区间
所以 离散化两性质:大小关系和是否相邻
线段树:
只需开一个数组来标记出现过的颜色即可
1 //#include<bits/stdc++.h> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 #include<string> 6 #include<iostream> 7 #define ll long long 8 const int maxn=1e5+5; 9 using namespace std; 10 11 int a[maxn],b[maxn],c[maxn*2]; 12 int lazy[maxn<<2]; 13 bool use[maxn<<2]; 14 int ans; 15 16 void pushdown(int rt) 17 { 18 if(lazy[rt]){ 19 lazy[2*rt]=lazy[2*rt+1]=lazy[rt]; 20 lazy[rt]=0; 21 } 22 } 23 void update(int L,int R,int l,int r,int rt,int add) 24 { 25 if(L<=l&&R>=r){ 26 lazy[rt]=add; 27 return ; 28 } 29 int mid=(l+r)>>1; 30 pushdown(rt); 31 if(L<=mid){ 32 update(L,R,l,mid,2*rt,add); 33 } 34 if(R>mid){ 35 update(L,R,mid+1,r,2*rt+1,add); 36 } 37 } 38 void query(int L,int R ,int l,int r,int rt) 39 { 40 if(lazy[rt]!=0){ 41 if(!use[lazy[rt]])ans++; 42 use[lazy[rt]]=1; 43 return ; 44 } 45 if(l==r){return ;} 46 int mid=(l+r)>>1; 47 if(L<=mid){ 48 query(L,R,l,mid,2*rt); 49 } 50 if(R>mid){ 51 query(L,R,mid+1,r,2*rt+1); 52 } 53 } 54 int main() 55 { 56 int t,k,m; 57 scanf("%d",&t); 58 while(t--){ 59 m=ans=0; 60 memset(use,0,sizeof(use)); 61 memset(lazy,0,sizeof(lazy)); 62 scanf("%d",&k); 63 for(int i=1;i<=k;i++) 64 { 65 scanf("%d%d",&a[i],&b[i]); 66 c[++m]=a[i];c[++m]=b[i]; 67 } 68 sort(c+1,c+m+1); 69 m=unique(c+1,c+m+1)-c; 70 m--; 71 for(int i=m;i>1;i--) 72 { 73 if(c[i]-1>c[i-1]){ 74 c[++m]=c[i-1]+1; 75 } 76 } 77 sort(c+1,c+m+1); 78 m=unique(c+1,c+m+1)-c; 79 for(int i=1;i<=k;i++){ 80 a[i]=lower_bound(c+1,c+m,a[i])-c; 81 b[i]=lower_bound(c+1,c+m,b[i])-c; 82 update(a[i],b[i],1,m-1,1,i); 83 } 84 query(1,m-1,1,m-1,1); 85 cout<<ans<<endl; 86 } 87 return 0; 88 }
纵使单枪匹马,也要勇闯天涯