[关闭]
@ysner 2018-07-19T21:23:59.000000Z 字数 1480 阅读 2207

[SCOI2015]国旗计划

贪心 倍增


题面

有一个大小为的环,其上有个区间(互不包含)。对每个区间分别回答,如果必须使用该区间,最少需要多少区间才能完全覆盖环。

解析

套路般地破环成链。区间能复制的也复制一边。

贪心显然,寻找一区间的后继者时,选左端点尽可能靠右、却又小于该区间右端点的区间。
(其实由于互不包含这一条件,排序以后,各区间左端点、右端点都具有单调性,所以说选右端点尽可能靠右的区间也可以)
于是可以预处理出每个区间的后继者。

注意到,暴跳铁定,用倍增优化一下(或者说离散化,但实际上还是要倍增)。

记得在最右边设个极大值防止它跳得听不下来。。。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define re register
  8. #define il inline
  9. #define ll long long
  10. #define max(a,b) ((a)>(b)?(a):(b))
  11. #define min(a,b) ((a)<(b)?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=5e5+100;
  16. int n,m,top,len,mx,f[25][N],tot;
  17. struct dat
  18. {
  19. int l,r,id;
  20. bool operator < (const dat &o) const {return (l<o.l)||(l==o.l&&r<o.r);}
  21. }a[N];
  22. int ans[N];
  23. bool vis[N];
  24. il ll gi()
  25. {
  26. re ll x=0,t=1;
  27. re char ch=getchar();
  28. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  29. if(ch=='-') t=-1,ch=getchar();
  30. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  31. return x*t;
  32. }
  33. il int work(re int x)
  34. {
  35. re int tar=a[x].l+m,now=x,res=0;
  36. fq(i,20,0)
  37. if(f[i][now]&&a[f[i][now]].r<tar) now=f[i][now],res+=(1ll<<i);
  38. return res+2;//开始区间和结束区间都没算
  39. }
  40. int main()
  41. {
  42. tot=n=gi();m=gi();
  43. fp(i,1,n)
  44. {
  45. a[i].l=gi(),a[i].r=gi();a[i].id=i;
  46. if(a[i].l>a[i].r) a[i].r+=m;
  47. else a[++tot]=(dat){a[i].l+m,a[i].r+m,i};
  48. }
  49. sort(a+1,a+1+tot);a[tot+1].r=2e9;
  50. re int ysn=1;
  51. fp(i,1,tot)
  52. {
  53. while(ysn<=tot&&a[ysn+1].l<=a[i].r) ++ysn;
  54. f[0][i]=ysn;
  55. }
  56. fp(i,1,20) fp(j,1,tot) f[i][j]=f[i-1][f[i-1][j]];
  57. fp(i,1,tot) if(a[i].l<=m) ans[a[i].id]=work(i);
  58. fp(i,1,n) printf("%d ",ans[i]);puts("");
  59. return 0;
  60. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注