Codeforces 612 D. The Union of k-Segments (非递归线段树+离散化)

Codeforces 612 D. The Union of k-Segments (非递归线段树+离散化)_第1张图片Codeforces 612 D. The Union of k-Segments (非递归线段树+离散化)_第2张图片

题意:给定一堆线段,求最后重叠了k次或以上的线段和点。

先操作,最后一次下推标记,所以尽管是区间修改,非递归写起来还是很简单。

维护两个线段树,一个维护线段的覆盖,一个维护点的覆盖。

对于线段[L,R],点修改的区间是[L,R],

区间修改中,用线段的左端点代表这条线段,所以区间修改的区间是[L,R-1]


在所有操作都结束之后下推标记,然后从左到右扫描线段输出答案即可。

输出答案的时候,只有在没有线段覆盖了k次或以上的时候,才需要考虑是否有点被覆盖了k次或以上。

因为如果线段包含点的话,点就不需要独立输出了。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define maxn 1000007
using namespace std;
//离散化部分 
int Rank[maxn<<1],Rn;
void SetRank(){//排序+去除重复元素
	sort(Rank+1,Rank+1+Rn);
	int I=1;
	for(int i=2;i<=Rn;++i) if(Rank[i]!=Rank[i-1]) Rank[++I]=Rank[i];
	Rn=I;
}
int GetRank(int x){//得到某个元素离散化后的下标
	int L=1,R=Rn,M;
	while(L^R){
		M=(L+R)>>1;
		if(Rank[M]<x) L=M+1;
		else R=M;
	} 
	return L;
}
//非递归线段树 
int N; 
int Add[maxn<<3];//区间覆盖次数 
int P[maxn<<3];//点覆盖次数 
void Build(int n){//建树 
	N=1;while(N < n+2) N <<= 1;
	memset(Add,0,sizeof(Add));
	memset(P,0,sizeof(P));
}
void Update(int L,int R){//区间更新
	//线段更新 
	for(int s=N+L-1,t=N+R;s^t^1;s>>=1,t>>=1){
		if(~s&1) ++Add[s^1];
		if( t&1) ++Add[t^1]; 
	}
	//点更新
	for(int s=N+L-1,t=N+R+1;s^t^1;s>>=1,t>>=1){
		if(~s&1) ++P[s^1];
		if( t&1) ++P[t^1]; 
	}
}
void PushDown(){//下推所有标记
	for(int i=1;i<N;++i){
		Add[i<<1]+=Add[i];
		Add[i<<1|1]+=Add[i];
		P[i<<1]+=P[i];
		P[i<<1|1]+=P[i];
	}
}
int n,k,l[maxn],r[maxn];
int main(void)
{
	while(~scanf("%d%d",&n,&k)){
		//输入 
		for(int i=Rn=0;i<n;++i){
			scanf("%d%d",&l[i],&r[i]);
			Rank[++Rn]=l[i];
			Rank[++Rn]=r[i];
		}
		//离散化 
		SetRank();
		//建树 
		Build(Rn);
		//更新树 
		for(int i=0;i<n;++i)
			Update(GetRank(l[i]),GetRank(r[i]));
		//下推标记 
		PushDown();
		//计算答案 
		int On=0,I=0;
		for(int i=1;i<=Rn;++i){//扫描覆盖情况
			if(Add[N+i]>=k){
				if(!On){//碰到线段的左端点,记录 
					l[++I]=Rank[i];
					On=1;
				}
			}
			else{
				if(On){//碰到线段的右端点,记录 
					r[I]=Rank[i];
					On=0;
				}
				else{//只有在不被线段覆盖时,才会考虑点是否被覆盖了k次或以上 
					if(P[N+i]>=k){//遇到被覆盖k次或以上的点,记录 
						l[++I]=Rank[i];
						r[I]=Rank[i];
					}
				}
			}
		}
		//输出结果 
		printf("%d\n",I);
		for(int i=1;i<=I;++i){
			printf("%d %d\n",l[i],r[i]);
		}
	}
return 0;
}




你可能感兴趣的:(Codeforces 612 D. The Union of k-Segments (非递归线段树+离散化))