標籤:
題目大意:給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;}
hihoCoder:#1079(線段樹+離散化)