1 条题解

  • 0
    @ 2025-8-24 21:52:12

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar SovietPower✨
    因你而起的一泓喜悲 权当年轻 留个纪念

    搬运于2025-08-24 21:52:12,当前版本为作者最后更新于2017-05-27 15:01:22,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这道题我有两种做法:线段树和浮水法(表示不会离散化,好在数据还用不到)。

    1. 线段树 维护区间是否被染色:区间修改没被染色的点,标记,++ans;如果区间的点全被染过色,那ans不变。

    2. 浮水法,专门解决这类区间染色问题:

    记录某一个线段是不是(或者是有一部分)浮到了最上面。

    上浮思想:设竖直平面中存在有一些高度不同的线段,当一个线段上方没有被其他线段挡着时,这个线段就可以上浮,如果一个线段(或是它的一部分)可以上浮到无限高,那么显然,这个线段(或这一部分)所在的高度是他所覆盖的这一个数轴范围内(将平面的无限低的地方看做有一个数轴)最高的。

    浮水法其实是一个递归的过程,首先,当一条线段满足上浮的条件时,让他上浮(用 while 循环控制),但是当他不满足上浮的条件时,将他被挡住的那一段切掉,然后接着递归的让他剩下的那部分上浮。

    (摘自http://www.cnblogs.com/SueMiller/archive/2011/08/05/2128794.html,网上没有很多相关的)

    补代码:1.线段树

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=10000005,M=1005;
    
    int n,m,Ans,A[M],B[M];
    bool flag,colored[N<<2];
    
    int read()
    {
        int now=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar();
        return now;
    }
    
    void PushUp(int rt)
    {
        colored[rt]= colored[rt<<1]&&colored[rt<<1|1];
    }
    
    /*void Build(int l,int r,int rt)
    {
        if(l==r)
          return;
        int m=(l+r)>>1;
        Build(l,m,rt<<1);
        Build(m+1,r,rt<<1|1);
        PushUp(rt);
    }*/
    
    void Modify(int l,int r,int rt,int L,int R)
    {
        if(colored[rt]) return;
        if(L<=l && r<=R)
        {
            flag=1;colored[rt]=1;
            return;
        }
        int m=(l+r)>>1;
        if(L<=m) Modify(l,m,rt<<1,L,R);
        if(m<R) Modify(m+1,r,rt<<1|1,L,R);
        PushUp(rt);
    }
    
    int main()
    {
        freopen("ha14d.in","r",stdin);
        freopen("ha14d.out","w",stdout);
        n=read();m=read();
    //    Build(1,n,1);
        for(int i=1;i<=m;i++)
          A[i]=read(),B[i]=read();
        for(int i=m;i>=1;i--)
        {
            flag=0;
            Modify(1,n,1,A[i],B[i]);
            if(flag) ++Ans;
        }
        printf("%d",Ans);
        fclose(stdin);fclose(stdout);
        return 0;
    }
    

    2.浮水法:

    #include<cstdio>
    using namespace std;
    const int N=10000005,M=1005;
    
    int n,m,Ans,cur,A[M],B[M];
    bool vis[M];
    
    int read()
    {
        int now=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9')now=(now<<3)+(now<<1)+c-'0',c=getchar();
        return now;
    }
    
    void Solve(int a,int b,int now)
    {
        if(vis[cur]) return;
        while(now<=m && (a>=B[now]||b<=A[now]))//需要等于 
          ++now;
        if(now>m)
          ++Ans,vis[cur]=1;//printf("%d:%d--%d\n",Ans,a,b);
        if(a<A[now] && A[now]<b) Solve(a,A[now],now+1);//不能等于 
        if(b>B[now] && B[now]>a) Solve(B[now],b,now+1);
    }
    
    int main()
    {
    //    freopen("ha14d.in","r",stdin);
    //    freopen("ha14d.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=m;i++)
          A[i]=read(),B[i]=read(),++B[i];//右端点再加1,因为两端点是都不能放其他海报的(看不见) 
        for(cur=m-1;cur>=1;cur--)
          Solve(A[cur],B[cur],cur+1);
        printf("%d",++Ans);
    //    fclose(stdin);fclose(stdout);
        return 0;
    }
    

    其实还可以暴力 :这题数据真水,暴力就能ac。cogs上加强了数据暴力只能80(还是挺高的)。

    • 1

    信息

    ID
    1323
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者