最近在学数据结构,好不容易做了一道紫题,发个题解纪念一下。
题目传送门
思路:
我们一步步来,首先看题目,线段包含关系,画个图,找一下特点。

由图可知,若线段 \(j\) 被线段 \(i\) 包含,则需满足 \(l_i\le l_j\le r_j\le r_i\) 。
接着想, \(l_i\le r_i\) 和 \(l_j\le r_j\) 是一定满足的,即我们只需要保证 \(l_i\le l_j\) 和 \(r_j\le r_i\) 。
一个条件总是要比两个要好求,那么我们不妨将这些线段的左端点或者右端点排一下序,这样就可以提前满足两个条件之一。
继续,排序后怎样维护左端点?(我这里是按右端点排序,排左端点也是同理)先看数据范围, \(-10^9\le l_i,r_i\le 10^9\) ,很大,所以要离散化。离散化后就有点类似于一个区间和的问题,用树状数组维护就可以了。
代码如下:
#include<iostream>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
const int MAXN=2e5+2;
struct lfxxx{
int l,r,op;
}a[MAXN];
int n,k,tree[MAXN<<1],b[MAXN],ans[MAXN];//注意所开数组空间
void add(int x){//树状数组基本修改操作
for(;x<=n;x+=lowbit(x))
tree[x]++;
}
int ask(int x){//树状数组查询
int ans=0;
for(;x;x-=lowbit(x))
ans+=tree[x];
return ans;
}
int find_(int l,int r,int x){//离散化二分查找
while(l<r){
int mid=((l+r+1)>>1);
x<b[mid]?r=mid-1:l=mid;
}
return l;
}
bool cmp(lfxxx x,lfxxx y){//按右端点排序
return x.r<y.r;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;a[i].op=i;//输入,并记录位置
b[i]=a[i].l;
}
sort(b+1,b+n+1);
k=unique(b+1,b+n+1)-b-1;//STL基本离散化
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
a[i].l=find_(1,k,a[i].l);
for(int i=1;i<=n;i++){
ans[a[i].op]=i-ask(a[i].l-1)-1;
add(a[i].l);
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<endl;
return 0;
}
谢谢!!!
浙公网安备 33010602011771号