洛谷——P2434 [SDOI2005]区间

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷——P2434 [SDOI2005]区间相关的知识,希望对你有一定的参考价值。

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:
5
5 6
1 4
10 10
6 9
8 10
输出样例#1:
1 4
5 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<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 410000
using 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<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 410000
using 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<b.l;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
     a[i].l=read(),a[i].r=read();
    sort(a+1,a+1+n,cmp);
    int l=a[1].l,r=a[1].r;
    for(int i=2;i<=n;i++)
    {
        if(a[i].l<=r) r=max(r,a[i].r);
        else 
        {
            printf("%d %d\n",l,r);
            l=a[i].l;r=a[i].r;
        }
    }
    printf("%d %d",l,r);
    return 0;
}

 

以上是关于洛谷——P2434 [SDOI2005]区间的主要内容,如果未能解决你的问题,请参考以下文章

P2434 [SDOI2005]区间

P2434 [SDOI2005]区间

洛谷 2434 [SDOI2005]区间

「SDOI2005」区间

洛谷 P1463 [SDOI2005]反素数ant

洛谷 P2335 [SDOI2005]位图