hihoCoder:#1079(线段树+离散化)
题目大意:给n个区间,有的区间可能覆盖掉其他区间,问没有完全被其他区间覆盖的区间有几个?区间依次给出,如果有两个区间完全一样,则视为后面的覆盖前面的。
题目分析:区间可能很长,所以要将其离散化。但离散化之后区间就变成了连续的,不再是离散的。也就是叶子由左右端点为u、u变成了左右端点为u-1、u,左右儿子有(l,mid)和(mid+1,r)变成了(l,mid)和(mid,r)。所以离散化之后要以长度为1的区间为叶子节点建立线段树,而不是以1、2、3...为叶子节点建线段树。
代码如下:
# include<iostream> # include<cstdio> # include<set> # include<map> # include<cstring> # include<algorithm> using namespace std; const int N=200000; int tr[N*4+5]; int n,m; int lazy[N*4+5]; int x[N+5],y[N+5]; set<int>s; map<int,int>mp; int num[N+5]; void pushDown(int rt,int l,int r) { if(lazy[rt]==-1) return ; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; tr[rt<<1]=tr[rt<<1|1]=tr[rt]; lazy[rt]=-1; } void update(int rt,int l,int r,int L,int R,int val) { if(L<=l&&r<=R){ tr[rt]=val; lazy[rt]=val; }else{ pushDown(rt,l,r); int mid=l+(r-l)/2; if(L<=mid) update(rt<<1,l,mid,L,R,val); if(R>mid) update(rt<<1|1,mid+1,r,L,R,val); } } void query(int rt,int l,int r) { if(l==r){ if(tr[rt]!=-1) s.insert(tr[rt]); return ; } if(lazy[rt]!=-1){ s.insert(tr[rt]); return ; } int mid=l+(r-l)/2; query(rt<<1,l,mid); query(rt<<1|1,mid+1,r); } int f(int l,int r,int x) { while(l<r){ int mid=l+(r-l)/2; if(num[mid]<x) l=mid+1; else r=mid; } return l; } int main() { while(~scanf("%d%d",&n,&m)) { num[0]=0; mp.clear(); for(int i=0;i<n;++i){ scanf("%d%d",x+i,y+i); if(mp[x[i]]==0) num[++num[0]]=x[i],++mp[x[i]]; if(mp[y[i]]==0) num[++num[0]]=y[i],++mp[y[i]]; } sort(num+1,num+num[0]+1); memset(tr,-1,sizeof(tr)); memset(lazy,-1,sizeof(lazy)); for(int i=0;i<n;++i){ int a=f(1,num[0]+1,x[i]); int b=f(1,num[0]+1,y[i]); update(1,1,num[0]-1,a,b-1,i); } s.clear(); query(1,1,num[0]-1); printf("%d\n",s.size()); } return 0; }