bzoj4082 [Wf2014]Surveillance 倍增

来源:互联网 发布:个人网络循环贷款利率 编辑:程序博客网 时间:2024/05/16 15:33

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);}
原创粉丝点击