bzoj4082 [Wf2014]Surveillance 倍增

该问题要求在环形结构上使用最少数量的区间完全覆盖环。给定环的长度和多个区间,通过建立连接并使用倍增算法求解最少区间数。样例输入和输出展示了具体的操作过程,最终解决方案在nlogn的时间复杂度内完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给你一个长度为len的环,以及n个区间,要你选择尽量少的区间,使得它们完全覆盖整个环。问最少要多少个区间。

Input

输入数据的第一行是两个整数len和n,代表环的长度以及区间个数。之后n行描述的是n个区间,每个区间分别用一对数字(a,b)表示,若a≤b则表示这个区间覆盖的是[a,b]部分,否则表示这个区间覆盖的是除掉[a+1,b-1]以外的其他部分。

Output

输出只有一行,一个整数,代表覆盖整个环所需要的最少区间个数。

Sample Input

100 7

1 50

50 70

70 90

90 40

20 60

60 80

80 20

Sample Output

3

一开始以为是什么区间问题,认真想了想觉得链的话随便做,环的话?
然后试了一下好像不能过。。没啥想法了,%一波po姐。
每个区间向它能跳到且右端点最远的区间连边,形成一棵树。
然后倍增一下,每个点向上倍增最少多少步可以走完这整个环。
nlogn居然能过。。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e6+5;
const int inf=0x3f3f3f3f;
int n,len,mn[N],fa[N][25];
struct node
{
    int l,r;
}a[N];
int ans;
bool cmp(node a,node b)
{
    return a.r<b.r;
}
int main()
{
    scanf("%d%d",&len,&n);
    fo(i,1,n)
    {
        scanf("%d%d",&a[i].l,&a[i].r);
        if (a[i].r<a[i].l)a[i].r+=len;
    }
    sort(a+1,a+1+n,cmp);
    mn[n+1]=inf;
    fd(i,n,1)mn[i]=min(a[i].l,mn[i+1]);
    int j=1;
    fo(i,1,n)
    {
        while (j<n&&mn[j+1]-1<=a[i].r)j++;
        if (j!=i)fa[i][0]=j;
    }
    fd(i,n,1)
    fo(j,1,20)fa[i][j]=fa[fa[i][j-1]][j-1];
    ans=inf;
    fo(i,1,n)
    {
        int x=i,s=1;
        fd(j,20,0)if (fa[x][j]&&a[fa[x][j]].r<a[i].l+len)x=fa[x][j],s+=1<<j;
        if (a[x].r<a[i].l+len-1&&fa[x][0])x=fa[x][0],s++;
        if (a[x].r>=a[i].l+len-1)ans=min(ans,s);
    }
    if (ans==inf)puts("impossible");
    else printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值