最近在学数据结构,好不容易做了一道紫题,发个题解纪念一下。

题目传送门

思路:

我们一步步来,首先看题目,线段包含关系,画个图,找一下特点。

由图可知,若线段 \(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;
}

谢谢!!!

posted on 2022-03-05 13:00  wuwenjiong  阅读(55)  评论(0)    收藏  举报