Codeforces 612 D. The Union of k-Segments (非递归线段树+离散化)
2015-12-28 23:13
453 查看
题意:给定一堆线段,求最后重叠了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;
}
相关文章推荐
- Logistic回归分析时几个需要注意的问题
- ExecutorService.invokeAny()和ExecutorService.invokeAll()的使用剖析
- HDU1455Sticks(dfs剪枝)
- Android获取屏幕宽高信息
- 又是一周-AJAX(三)
- 对大盘的一些看法
- EditText 代码设置光标颜色(反射)
- 20150916谱聚类.md(图片版)
- 数学中的术语与常用表达
- BZOJ 2190 - 欧拉函数的应用(数据范围不同 -> 做法不同 -> 启示)
- Linux下USB转串口的驱动
- Python笔记-几种取整方式
- (转)(contant的一些用法)
- AngularJS中Directive间交互实现合成
- Mac & Xcode 技巧
- linux:shell:tree
- 在线生成简单二维码图片
- Android之SwipeRefreshLayout
- js简单对象
- 线性拟合——从最大似然估计到平方误差到huber loss