题目链接:

https://ac.nowcoder.com/acm/contest/297#question

C-little w and Segment Coverage

题意:给M个区间,把每个区间上的点都加1,然后问删除哪一个点后不会被覆盖的点最少
我觉得这道题挺好的,就适合我们这些小白做,看题解能够收获很多~
哇,线段树原来还阔以统计区间内小于等于某个数x的个数有多少个呀,我太挫了,这个竟然没想到,经宋大佬指导后理解了,只要这段区间内的最小值都小于x的话,那么这段区间不就是个数了蛮

然后删除这段区间,那么这段区间的每个值不就都会减少1嘛,所以能覆盖的点其实就是值大于等于2的点,所以直接找大于等于2的点的个数就行了

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
int N,M;
int Min[maxn<<2],a[maxn];
void pushup(int id)
{
	Min[id]=min(Min[id<<1],Min[id<<1|1]);
}
void Build(int id,int L,int R)
{
	Min[id]=1e9;
	if(L==R)Min[id]=a[L]; 
	else
	{
		int mid=L+R>>1;
		Build(id<<1,L,mid);
		Build(id<<1|1,mid+1,R);
		pushup(id);
	}
}
int query(int id,int L,int R,int qL,int qR,int val)//求[qL,qR]内大于等于val的有多少个 
{
	if(L==R)
	{
		if(Min[id]>=val)return 1;
		else return 0;
	}
	if(qL<=L&&qR>=R && Min[id]>=val)return(R-L+1);
	else
	{
		int mid=L+R>>1;
		int res=0;
		if(qL<=mid)res+=query(id<<1,L,mid,qL,qR,val);
		if(qR>=mid+1)res+=query(id<<1|1,mid+1,R,qL,qR,val);
		return res;
	}
}
int L[maxn],R[maxn];
int main()
{
	while(cin>>N>>M)
	{
		memset(a,0,sizeof a);
		for(int i=1;i<=M;i++)
		{
			scanf("%d%d",L+i,R+i);
			a[L[i]]++,a[R[i]+1]--;
		}
		int cnt=0;
		for(int i=1;i<=N;i++)
		{
			a[i]+=a[i-1];
			if(a[i]==0)cnt++;
		}
		Build(1,1,N);
		int ans=0;
		int MIN=N,pos=-1;//MIN表示删除一条边最少会增加多少个点不能被覆盖 
		for(int i=1;i<=M;i++)
		{
			int l=L[i],r=R[i];
			int ans=r-l+1-query(1,1,N,l,r,2);
			if(ans<=MIN)
			{
				MIN=ans;
				pos=i;
			}
		}
		cout<<pos<<" "<<cnt+MIN<<endl;
	}
}

官方题解

官方题解没有用线段树,而是直接找值为1的数,然后看区间内值为1的数有多少个,如果删去这条边,那么值为1的就变成0了,那这些点就肯定不会被覆盖到了,就是这样统计的

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
int N,M;
int a[maxn],sum[maxn],L[maxn],R[maxn];
int main()
{
	while(cin>>N>>M)
	{
		memset(a,0,sizeof a);
		memset(sum,0,sizeof sum);
		for(int i=1;i<=M;i++)
		{
			scanf("%d%d",L+i,R+i);
			a[L[i]]++,a[R[i]+1]--;
		}
		int cnt=0;
		for(int i=1;i<=N;i++)
		{
			a[i]+=a[i-1];
			if(a[i]==0)cnt++;
			if(a[i]==1)sum[i]=1;
			sum[i]+=sum[i-1];
		}
		int MIN=N,pos=-1;
		for(int i=1;i<=M;i++)
		{
			int l=L[i],r=R[i];
			int ans=sum[r]-sum[l-1];
			if(ans<=MIN)
			{
				MIN=ans;
				pos=i;
			}
		}
		cout<<pos<<" "<<cnt+MIN<<endl;
	}
}