思路:扫描线||树状数组
一,扫描线:题目意思为求每一点的线段覆盖数,因此可以将左端点用 1表示线段开始,右端点用-1表示线段结束,然而右端点也属于线段,因此可以将改为 右端点+1用 -1 表示,在将所有点由小到大排序再遍历一遍,sum记录其值,因此遍历到 i点时sum就为 i点的线段覆盖数。
二,树状数组:原理和扫描线类似,将 左端点和 右端点+1 分别用1,-1表示,而第i点的覆盖数即为前i点的端点值总和,在初始化时,用 Update(l,1)和 Update(r+1,-1) ,则 Query(i) 即为第i点的答案。
三,将用数组d[i]直接存储扫描线的左右端点即可,不用排序。。
Code 扫描线:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct node{
int id;
int s;
bool operator<(const node &p)const{
return id<p.id;
}
};
const int MAX_N=100005;
int n;
vector<node> ive;
int ans[MAX_N];
int main()
{
ios::sync_with_stdio(false);
int l,r;
while(cin>>n&&n){
ive.clear();
for(int i=0;i<n;++i)
{
cin>>l>>r;
ive.push_back(node{l,1});
ive.push_back(node{r+1,-1});
ans[i+1]=0;
}
sort(ive.begin(),ive.end());
int sum=0,k=0;
for(int i=1;i<=n&&k<2*n;++i)
{
while(k<2*n&&ive[k].id<=i){
sum+=ive[k++].s;
}
ans[i]=sum;
}
cout<<ans[1];
for(int i=2;i<=n;++i)
cout<<" "<<ans[i];
cout<<endl;
}
return 0;
}
Code 树状数组:
#include<iostream>
#include<cstring>
using namespace std;
const int MAX_N=100005;
int n;
int c[MAX_N];
int Lowbit(int x);
void Update(int id,int x);
int Query(int id);
int main()
{
ios::sync_with_stdio(false);
int l,r;
while(cin>>n&&n){
memset(c,0,sizeof(c));
for(int i=0;i<n;++i)
{
cin>>l>>r;
Update(l,1); Update(r+1,-1);
}
cout<<Query(1);
for(int i=2;i<=n;++i)
cout<<" "<<Query(i);
cout<<endl;
}
return 0;
}
int Lowbit(int x)
{
return x&(-x);
}
void Update(int id,int x)
{
while(id<=n){
c[id]+=x;
id+=Lowbit(id);
}
}
int Query(int id)
{
int ans=0;
while(id>0){
ans+=c[id];
id-=Lowbit(id);
}
return ans;
}
Code 3:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N=1e5+5;
int n;
int d[MAX_N];
int main()
{
int l,r,ans;
while(~scanf("%d",&n)&&n){
for(int i=1;i<=n;i++)
{
scanf("%d%d",&l,&r);
d[l]+=1; d[r+1]-=1;
}
ans=d[0]=d[n+1]=0;
for(int i=1;i<n;++i)
{
ans+=d[i]; d[i]=0;
printf("%d ",ans);
}
ans+=d[n]; d[n]=0;
printf("%d\n",ans);
}
return 0;
}