• POJ


    题目链接
    题意:
    n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000) 。求出最后还能看见多少张海报。

    分析1

    离散化:典型的区间染色问题,可以用线段树求解,但是如果直接建一般的线段树树,会超内存,而且时间复杂度相当危险,可以考虑离散化,但是又有一个坑点就是离散化会破坏区间的连续性。
    比如,数据
    1
    3
    1 4
    1 1
    4 4
    这个答案明显是3,但是直接离散化的话答案会输出2;
    因此我们再输入排序去重后,需要在临时数组里加入一条语句,之后再排一下序,最后lower_bound() 离散化

    if(temp[i]-temp[i-1]>1) temp[++tot]=temp[i-1]+1; //temp[]是用于离散化的临时数组,tot是总数

    这样就能解决上面例子区间丢失连续性的问题
    (有可能你认为 把上面数据里的 1 1改成 1 2 会卡掉这个方法,但是这是必不可能的,因为这个方法是在已经排序去重后使用的,没有理解可以手动模拟一下);

    代码

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int N=100000+5;
    const int inf=0x3f3f3f3f;
    #define ls (i<<1)
    #define rs (i<<1|1)
    int tree[N<<2],lazy[N<<2];
    int L[N],R[N],temp[N<<2],tot,len,ans;
    bool vis[N];
    void init()
    {
        memset(tree,0,sizeof(tree) );
        memset(lazy,0,sizeof(lazy) );
        memset(vis,0,sizeof(vis) );
        tot=len=ans=0;
    }
    void pushdown(int i,int l,int r)
    {
        lazy[ls]=lazy[rs]=lazy[i];
        tree[ls]=tree[rs]=lazy[i];
        lazy[i]=0;
    }
    void update(int i,int l,int r,int ll,int rr,int v)
    {
        if(ll<=l&&r<=rr)
        {
            lazy[i]=v;
            tree[i]=v;
            return;
        }
        if(lazy[i] ) pushdown(i,l,r);
        int mid=(l+r)>>1;
        if(mid>=ll) update(ls,l,mid,ll,rr,v);
        if(mid<rr) update(rs,mid+1,r,ll,rr,v);
        if(tree[ls]==tree[rs] ) tree[i]=tree[ls];
        else
            tree[i]=-1;
    }
    void query(int i,int l,int r,int ll,int rr)
    {
        if(ll<=l&&r<=rr&&tree[i]!=-1)
        {
            if(tree[i]&&!vis[tree[i] ]) ans++;
            vis[tree[i] ]=1;
            return;
        }
        if(lazy[i] ) pushdown(i,l,r);
        int mid=(l+r)>>1;
        if(mid>=ll) query(ls,l,mid,ll,rr);
        if(mid<rr) query(rs,mid+1,r,ll,rr);
    }
    int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch) )
        {
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(isdigit(ch) )
        {
            x=10*x+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    int main()
    {
        int T=read();
        while(T--)
        {
            init();
            int n;
            n=read();
            for(int i=1;i<=n;i++)
            {
                L[i]=read();
                R[i]=read();
                temp[++tot]=L[i];
                temp[++tot]=R[i];
            }
            sort(temp+1,temp+tot+1);
            len=unique(temp+1,temp+tot+1)-temp;
            int m=len;
            for(int i=1;i<m;i++)
                if(temp[i+1]-temp[i]>1) temp[++len]=temp[i]+1,tot++;
    
            sort(temp+1,temp+len+1);
            for(int i=1;i<=n;i++)
            {
                L[i]=lower_bound(temp+1,temp+len+1,L[i] )-temp;
                R[i]=lower_bound(temp+1,temp+len+1,R[i] )-temp;
                update(1,1,len,L[i],R[i],i);
            }
            query(1,1,len,1,len);
            printf("%d
    ",ans);
        }
        return 0;
    }

    分析2

    浮水法:由于是从前往后覆盖,答案由后面的海报先决定,那如果我们从后往前处理,前面海报的操作便不会对后面造成影响(可以节省时间和空间),故只需通过0 1 两种状态来判断是否被覆盖,用一个标记flag,如果当前区间没被覆盖且当前区间在目标区间内,则flag=1,更新结束后ans++。

    实现方法:只需要一个更新函数即可,不需要lazy延时标记。

    代码

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int N=10000000+5;
    const int inf=0x3f3f3f3f;
    #define ls (i<<1)
    #define rs (i<<1|1)
    bool tree[N<<2],flag;  //1表示已经被后贴的海报覆盖
    int L[10005],R[10005];
    void update(int i,int l,int r,int ll,int rr)
    {
        if(tree[i]) return;  //如果后贴的海报已经覆盖
        if(ll<=l&&r<=rr)
        {
            tree[i]=flag=1;
            return;
        }
        //printf("%d %d
    ",l,r);
        int mid=(l+r)>>1;
        if(mid>=ll)
            update(ls,l,mid,ll,rr);
        if(mid<rr)
            update(rs,mid+1,r,ll,rr);
        tree[i]=tree[ls]&&tree[rs];
    }
    int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch) )
        {
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(isdigit(ch) )
        {
            x=10*x+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    int main()
    {
        int T=read();
        while(T--)
        {
            int n;
            n=read();
            int maxn=0;
            for(int i=1;i<=n;i++)
            {
                L[i]=read();
                R[i]=read();
                maxn=max(maxn,R[i] );
            }
            int ans=0;
            for(int i=n;i>=1;i--) //浮水法,先处理最后的
            {
                flag=0;
                update(1,1,maxn,L[i],R[i] );
               // printf("%d %d %d
    ",L[i],R[i],flag);
                if(flag) ans++;
            }
            printf("%d
    ",ans);
            memset(tree,0,sizeof(tree) );
        }
        return 0;
    }
  • 相关阅读:
    转载 Oracle常用函数
    转载:ASP.NET Request对象使用实例浅析
    JQuery's Ajax request a datatable
    转载 WCF VS ASPNET WEB SERVICE
    转载 浅谈C#中构造函数与析构函数
    javascript正则表达式 实现Trim()
    转载: NET中使用log4net记录日志
    Consuming WCF / ASMX / REST service using JQuery
    asp.net下使用Request.Form获取非服务器控件的值的方法
    如何把Access转成SQL Server的方法介绍
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12025218.html
Copyright © 2020-2023  润新知