题意:一维的墙上,n个人去贴海报,海报覆盖一定的区间,后贴的可能覆盖先贴的,问最后能看到多少张海报。
思路:线段树(区间更新)+离散化。因为墙的范围太大,n的范围小,所以需要离散化。离散化时注意如果两点不连续,需要在中间插入一个点,不然会出现bug。
#include <iostream> #include <stdio.h> #include <cmath> #include <algorithm> #include <iomanip> #include <cstdlib> #include <string.h> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <ctype.h> #define ll long long using namespace std; int pl[20010]; int pr[20010]; int post[40010]; struct node{ int l; int r; int val; bool flag; }; node tree[160010]; void build_tree(int n,int l,int r){ tree[n].l=l; tree[n].r=r; tree[n].flag=0; if(l==r)return; int mid=(l+r)/2; build_tree(n*2,l,mid); build_tree(n*2+1,mid+1,r); } void update(int n,int l,int r,int v){ if(tree[n].l==l&&tree[n].r==r){ tree[n].val=v; tree[n].flag=1; return; } int mid=(tree[n].l+tree[n].r)/2; if(tree[n].flag){ tree[n].flag=0; update(n*2,tree[n].l,mid,tree[n].val); update(n*2+1,mid+1,tree[n].r,tree[n].val); } if(r<=mid){ update(n*2,l,r,v); }else{ if(l<=mid){ update(n*2,l,mid,v); update(n*2+1,mid+1,r,v); }else{ update(n*2+1,l,r,v); } } } void query(int n,int l,int r){ if(tree[n].flag){ post[tree[n].val]=1; return; } if(l==r)return; int mid=(l+r)/2; query(n*2,l,mid); query(n*2+1,mid+1,r); } map<int,int> mp; int main(){ int t; cin>>t; while(t--){ memset(post,0,sizeof(post)); mp.clear(); int n; cin>>n; for(int i=1;i<=n;i++){ scanf("%d%d",&pl[i],&pr[i]); mp[pl[i]]=1; mp[pr[i]]=1; } int cnt=1; map<int,int>::iterator last=mp.begin(); for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){ if(last!=it&&last->first+1<it->first)cnt++;//在不连续的点中间插入点,防止中间点被忽略 it->second=cnt++; last=it; } build_tree(1,1,cnt-1); for(int i=1;i<=n;i++){ update(1,mp[pl[i]],mp[pr[i]],i); } query(1,1,cnt-1); int ans=0; for(int i=1;i<cnt;i++)if(post[i])ans++; cout<<ans<<endl; } return 0; }