cogs1682. [HAOI2014]贴海报 x

1682. [HAOI2014]贴海报

★★☆   输入文件:ha14d.in   输出文件:ha14d.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

Bytetown城市要进行市长竞选,所有的选民可以畅所欲言地对竞选市长的候选人发表言论。为了统一管理,城市委员会为选民准备了一个张贴海报的electoral墙。

张贴规则如下:

1.electoral墙是一个长度为N个单位的长方形,每个单位记为一个格子;

2.所有张贴的海报的高度必须与electoral墙的高度一致的;

3.每张海报以“A B”表示,即从第A个格子到第B个格子张贴海报;

4.后贴的海报可以覆盖前面已贴的海报或部分海报。

现在请你判断,张贴完所有海报后,在electoral墙上还可以看见多少张海报。

【输入格式】

第一行:     N   M            分别表示electoral墙的长度和海报个数

接下来M行:   Ai   Bi          表示每张海报张贴的位置

 

【输出格式】

输出贴完所有海报后,在electoral墙上还可以看见的海报数。

【样例输入】

 

100 5

1 4

2 6

8 10

3 4

7 10

 

【样例输出】

4

【提示】

 

【约束条件】

1 0<= N <= 10000000     1<=M<=1000   1<= Ai <= Bi <=10000000

所有的数据都是整数。数据之间有一个空格

 思路:

  1)首先这道题暴力可以拿80分!(在luogu上可以AC!!!!)

  2)然后考场上作死写了个并查集。。。61分

  3)正解:

      ①线段树(然而我没写~)

      ②浮水法

坑点:

  因为给出的是所位于的块,不是左右端点,所以在处理浮水法的时候记得要右端点+1,或者左端点-1

上代码:

1)暴力

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
 
const int M = 1e7 + 1;
int n,m,l,r,ans;
int a[M],v[M];

inline int reads()
{
    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=10*x+ch-'0';ch=getchar();}
    return x*f;
}

int main()
{
    freopen("ha14d.in","r",stdin);
    freopen("ha14d.out","w",stdout);
    n=reads(),m=reads();
    for(int i=1;i<=m;i++)
    {
        l=reads(),r=reads();
        if(r<l) swap(l,r);
        for(int j=l;j<=r;j++)
            a[j]=i;
    }
    for(int i=1;i<=n;i++)
    {
        if(!v[a[i]] && a[i])
        {
            ans++;
            v[a[i]]=1;
        }
    }
    printf("%d",ans);
    return 0;
}

2)作死并查集

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
 
using namespace std;
 
inline int reads()
{
    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=10*x+ch-'0';ch=getchar();}
    return x*f;
}
 
const int M = 1e7 + 2333333;                ///多开几个 
const int N = 1111;
int n,m;
int f[M];
int ans[M],anse;
int Ls[N],Rs[N];
 
int getf(int x)
{return f[x] == x ? x : f[x] = getf(f[x]);}
 
int main()
{
    freopen("ha14d.in","r",stdin);
    freopen("ha14d.out","w",stdout);
    n=reads();m=reads();                    ///n是n块,不是左右端点!!! 
    for(int i=1;i<=n+2;i++)
        f[i]=i;
    for(int i=1;i<=m;i++)                   ///m组数据 
    {                                       ///手动从1开始,从0不会... 
        Ls[i]=reads();
        Rs[i]=reads()+1;                    ///因为给出不是点的坐标,是块的坐标 
    }
    int l,r; 
    for(int i=m;i>=1;i--)                   ///逆序张贴,因为只需要的是最后的能看到的海报 
    {
        l=Ls[i],r=Rs[i];                    ///左右端点 
        if(l>r) swap(l,r);                  ///maybe?会出现"left">"right"的情况(考虑最坏情况,以防万一,以前做过一个题就是恶心的数据!) 
        for(int j=getf(l);j<=r;j=getf(j+1))
        {
            f[getf(j)]=getf(j+1);           ///将当前被张贴报纸的父结点手动设置到最后一个的父结点 
///            ans[j]=i;
            ans[i]++; 
            if(getf(1)==n+2) break;         ///表示已经贴完 
        }
    }
 
    for(int i=1;i<=n+1;i++)
    {
///        printf("%d=%d\n",i,ans[i]);      ///输出调试??? 
        if(ans[i]) anse++;
    }
    printf("%d\n",anse);
 
    return 0;
}

3)正解(浮水法)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
 
const int M = 1001;
int n,m,ans=1;
bool v[M];
 
struct U {
    int l,r,id;
    //id 为第几张海报 
}t[M];
 
inline int reads()
{
    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=10*x+ch-'0';ch=getchar();}
    return x*f;
}
 
void swim(int ql,int qr,int nowid,int preid)
{
    if(v[preid])
        return;
    while(nowid<=m && (qr<=t[nowid].l || ql>=t[nowid].r))
        nowid++;
    if(nowid>m)
    {
        v[preid]=true;
        ans++;
        return;
    }
    if(ql<t[nowid].l && qr>t[nowid].l)
        swim(ql,t[nowid].l,nowid+1,preid);
    if(ql<t[nowid].r && qr>t[nowid].r)
        swim(t[nowid].r,qr,nowid+1,preid);
}
 
int main()
{
    freopen("ha14d.in","r",stdin);
    freopen("ha14d.out","w",stdout);
    n=reads();m=reads();
    for(int i=1;i<=m;i++)
    {
        t[i].l=reads(),t[i].r=reads()+1;
        t[i].id=i;
    }
    for(int i=m-1;i>=1;i--)
        swim(t[i].l,t[i].r,i+1,i);
    printf("%d",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/zxqxwnngztxx/p/7156937.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值