博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷——P2434 [SDOI2005]区间
阅读量:7005 次
发布时间:2019-06-27

本文共 3411 字,大约阅读时间需要 11 分钟。

P2434 [SDOI2005]区间

题目描述

现给定n个闭区间[ai, bi],1<=i<=n。这些区间的并可以表示为一些不相交的闭区间的并。你的任务就是在这些表示方式中找出包含最少区间的方案。你的输出应该按照区间的升序排列。这里如果说两个区间[a, b]和[c, d]是按照升序排列的,那么我们有a<=b<c<=d。

请写一个程序:

读入这些区间;

计算满足给定条件的不相交闭区间;

把这些区间按照升序输出。

输入输出格式

输入格式:

 

第一行包含一个整数n,3<=n<=50000,为区间的数目。以下n行为对区间的描述,第i行为对第i个区间的描述,为两个整数1<=ai<bi<=1000000,表示一个区间[ai, bi]。

 

输出格式:

 

输出计算出来的不相交的区间。每一行都是对一个区间的描述,包括两个用空格分开的整数,为区间的上下界。你应该把区间按照升序排序。

 

输入输出样例

输入样例#1:
55 61 410 106 98 10
输出样例#1:
1 45 10

 

 

思路:先使用很基础的操作,也就是线段覆盖的方式,将每一条线段插入线段树。最后求区间的做法是这样子的:

设两个变量a,b。一开始都让他们等于1.开个while(b<=n);每次查询区间【a,b】是否被完全覆盖。是的话,b++;不是的话判断a是否等于b,如果等于。a++,b++;如果a不等于b那么输出a b;然后a=b。

最后跳出循环时也要判断a是否等于b,等于的话程序结束。不等于的话输出a b,其实也就是a n。程序结束

注意一个地方!

我们在进行修改的时候修改的是一段区间,但是我们线段树中的这段区间与我们所说的区间有一点不一样,例如样例中的1~4,5~6,我们如果用线段树进行修改的话我们修改出来的会是

1 1  1 1 1 1 也就是说我们将1~6整个区间都给修改了,但是我们所说的修改是要将其变成1 1 1 0 1 1 也就是说4这个点不进行修改。那么我们在修改的时候就讲尾节点-1以后再进行区间修改就好了。

代码:

#include
#include
#include
#include
#include
#define N 410000using namespace std;int n,m,x,y,xx[N],yy[N],ans,sum;int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){
if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f;}struct Tree{ int l,r,w,f; }tree[N];void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(tree[k].l==tree[k].r) { tree[k].w=0; return ; } int m=(l+r)>>1; build(k<<1,l,m); build(k<<1|1,m+1,r); }int down(int k){ tree[k<<1].f=tree[k].f; tree[k<<1|1].f=tree[k].f; tree[k<<1].w=tree[k<<1].r-tree[k<<1].l+1; tree[k<<1|1].w=tree[k<<1|1].r-tree[k<<1|1].l+1; tree[k].f=0;}void change_interval(int k){ if(tree[k].l>=x&&tree[k].r<=y) { tree[k].w=tree[k].r-tree[k].l+1; tree[k].f=1; return; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(x<=m) change_interval(k<<1); if(y>m) change_interval(k<<1|1); tree[k].w=tree[k<<1].w+tree[k<<1|1].w;}void ask_interval(int k){ if(tree[k].l>=x&&tree[k].r<=y) { ans+=tree[k].w; return; } if(tree[k].f) down(k); int m=(tree[k].l+tree[k].r)>>1; if(x<=m) ask_interval(k<<1); if(y>m) ask_interval(k<<1|1);} int main() { n=read(); for(int i=1;i<=n;i++) xx[i]=read(),yy[i]=read(),m=max(m,max(xx[i],yy[i])); build(1,1,m); for(int i=1;i<=n;i++) x=xx[i],y=yy[i]-1,change_interval(1); x=1,y=1; while(y<=m) { ans=0;ask_interval(1); if(ans==y-x+1) y++; else { if(x==y) x++,y++; else { printf("%d %d\n",x,y); x=y; } } } if(x!=y) printf("%d %d",x,m); return 0; }

 

 

原来是打算用来练线段树的一道题,结果做了一下午,而且这道题暴力,贪心,前缀和都可以做!!!!

唉,发一个贪心的吧、、、按左端点排序后,记录当前区间[L,R],如果新的区间的l<=R,说明新的区间可以合并,更新R,如果新的区间l>R,说明新的区间不能跟当前区间合并,又因为已经按左端点拍了序,所以输出当前区间。

 

#include
#include
#include
#include
#include
#define N 410000using namespace std;int n,m,x,y,ans,sum;int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){
if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f;}struct A{ int l,r;}a[N];int cmp(A a,A b){ return a.l

 

转载于:https://www.cnblogs.com/z360/p/7486285.html

你可能感兴趣的文章
bash on AIX
查看>>
安装vue
查看>>
产品各类型之间的关系
查看>>
实时Web与WebSocket实践
查看>>
tomcat+eclipse远程调试
查看>>
windows——清空网络连接缓存
查看>>
postgresql用户管理
查看>>
枚举的基础类型
查看>>
eclipse查看一个方法被谁引用(调用)的快捷键四种方式
查看>>
Docker的学习笔记。
查看>>
怎样将eclipse与tomcat关联进行web开发
查看>>
Drools stream integration
查看>>
自建邮件系统如何选择服务器
查看>>
solr 3.5 配置及服务器设置
查看>>
tomcat 记录 访问者 ip + 访问地址
查看>>
thinkphp3.0基础模板引擎变量为空时输出默认值
查看>>
Mysql 安装服务
查看>>
nginx1.10.1学习之搭建静态资源服务器
查看>>
ubuntu下svn使用指南
查看>>
centos中的网络管理
查看>>