Description
Input
Output
Sample Input
1 5 1 4 2 6 8 10 3 4 7 10
Sample Output
4
题意:给每个区间贴纸,后面贴的会覆盖前面贴的,问最后能看到的纸有几张
思路:很明显的线段树区间更新问题,但是由于数目大,所以我们要考虑离散化,由于之前没有弄过离散化,看了人家的代码,再加上自己的演草纸上模拟过程,终于弄懂了离散的原理。
首先,我们将区间存放在一个map数组之中,通过s的结构体,我们可以将每个点,与其相对应的区间序号整理起来,然后排序,为了方便判断,将左区间记为负数
通过S,我们重新将数据存入map数组之中,这次map数组存放的是他们位置的区间,由于n只有10000,所以位置最大也就只有10000位,如果存数值则要10000000的空间,泽阳无论在空间还有时间上都得到了优化
例如样例中输入后
排序:1,2,3,4,6,7,8,10
对应位置:1,2,3,4,5,6,7,8
这样我们可以看到,以位置来建树只需要8个空间,但是如果用数值大小来建树则需要10个空间,在当位置与数字的大小差很大的时候,存放位置能优化更多的时间与空间
而现在,map数组中存放的是
1,4
2,5
7,8
3,4
6,8
可以发现,这些位置所对应的数字便是原本题目给出的数字区间,所以我们最后只要求出这些位置覆盖后有几个可见即可
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int n,cnt; const int maxn = 10000+10; struct node { int l,r,n;//n统计颜色 } a[maxn<<2]; struct kode { int point,num;//point记录区间的边,num记录位置 } s[maxn<<2]; int map[maxn<<1][2],ans,flag[maxn<<1]; int cmp(kode x,kode y) { return x.point<y.point; } void init(int l,int r,int i)//建树 { a[i].l = l; a[i].r = r; a[i].n = 0; if(l!=r) { int mid = (l+r)>>1; init(l,mid,2*i); init(mid+1,r,2*i+1); } } void insert(int i,int l,int r,int m) { if(a[i].l == l && a[i].r == r)//找到了区间,更新这个区间的颜色 { a[i].n = m; return; } int mid = (a[i].l+a[i].r)>>1; if(a[i].n>0)//重点注意,如果这个区间被访问了,并且这个区间有颜色,就要将这个区间的颜色更新到其左右孩子的节点,并且要将这个区间的颜色清空,这样才能算是覆盖 { a[2*i].n = a[2*i+1].n = a[i].n; a[i].n = 0; } if(l>=a[2*i+1].l) insert(2*i+1,l,r,m); else if(r<=a[2*i].r) insert(2*i,l,r,m); else { insert(2*i,l,mid,m); insert(2*i+1,mid+1,r,m); } } void solve(int i) { if(a[i].n)//如果有这个区间有颜色了,马上停止访问并返回,因为下面的无论有没有颜色都是已经被覆盖的了 { if(!flag[a[i].n])//乳沟有颜色且没被统计过的,就统计一次 { ans++; flag[a[i].n] = 1; } return; } solve(2*i); solve(2*i+1); return; } int main() { int t,i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i = 0; i<n; i++)//离散化 { scanf("%d%d",&map[i][0],&map[i][1]); s[2*i].point = map[i][0]; s[2*i+1].point = map[i][1]; s[2*i].num = -(i+1); s[2*i+1].num = i+1; } sort(s,s+2*n,cmp); int tmp = s[0].point,cnt = 1; for(i = 0; i<2*n; i++) { if(tmp != s[i].point)//如果和前面的不同,这迭代加1 { cnt++; tmp = s[i].point; } if(s[i].num<0) map[-s[i].num-1][0] = cnt; else map[s[i].num-1][1] = cnt; } init(1,cnt,1); for(i = 0; i<n; i++) insert(1,map[i][0],map[i][1],i+1); memset(flag,0,sizeof(flag)); ans = 0; solve(1); printf("%d\n",ans); } return 0; }