CF1175E Minimal Segment Cover(并查集/倍增)

CF1175E Minimal Segment Cover(并查集/倍增)

(倍增做法就不讲了)

将线段\([l,r]\)按照\(l\)排序,对于每个前缀的l就能求出最大的\(r\)

当我们不断增大\(r\)时,当前\(l\)对应位置的覆盖就不能满足询问所需,就需要不断向右边寻找最优的线段完成覆盖

每次接上去一个最优的线段被更新的答案是一个集合,也就是所有以它为最优线段的答案

这个我们可以用带权并查集维护

然后对于当前询问的\(r\),我们就可以直接在并查集上找到它的答案,当然这需要离线

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define reg register
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

char IO;
inline int rd(){
	int s=0,f=0;
	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}


const int N=5e5+10,P=2015;



int n,m;

struct Seg{
	int l,r,id;
	void Get(){ l=rd(),r=rd(); }
	bool operator < (const Seg __) const {
		return r<__.r;
	}
} Q[N];

int fa[N],maxr[N];
ll dis[N];
int Find(int x){
	if(fa[x]==x) return x;
	int f=fa[x];
	fa[x]=Find(fa[x]);
	dis[x]+=dis[f];
	return fa[x];
}

int ans[N];

int main(){
	n=rd(),m=rd();
	rep(i,1,n) {
		int l=rd(),r=rd();
		maxr[l]=max(maxr[l],r);
	}
	rep(i,0,5e5) fa[i]=i;
	rep(i,1,m) {
		Q[i].Get();
		Q[i].id=i;
	}
	sort(Q+1,Q+m+1);
	int ma=-1,p=1;
	rep(i,0,5e5) {
		ma=max(ma,maxr[i]);//同步维护最优的线段,可以直接用数组存下来
		while(p<=m && Q[p].r<=i) {
			int t=Q[p].l;
			Find(t);
			if(dis[t]<1e9) ans[Q[p].id]=dis[t];
			else ans[Q[p].id]=-1;
			p++;
		}//回答询问
		if(ma<=i) dis[i]=1e9;
		else fa[i]=ma,dis[i]=1;//将最优的线段接上去
	}
	rep(i,1,m) printf("%d\n",ans[i]);
}

posted @ 2020-02-06 10:36  chasedeath  阅读(224)  评论(0编辑  收藏  举报