bzoj 4444: [Scoi2015]国旗计划

Description

A国正在开展一项伟大的计划——国旗计划。这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈.这项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的边防战上作为这项计划的候选人。
A国幅员辽阔,边境线上设有M个边防站,顺时针编号1至M。每名边防战士常驻两个边防站,并且善于
在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这个边防战士的奔袭区间。n名边防战士都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。
现在,国十安全局局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线,从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必须参加国旗计划的前提下,至少需要多少名边防战士才能覆盖全部边境线,从而顺利地完成国旗计划.

解题报告

用时:1h40min,2WA
太菜了,这题不会....
首先要意识到对于一个点 (i),要选能够覆盖到 (i) 的最大右端点,这样显然更优,这个右端点可以 (O(n)) 求出 ,设为 (f[i]).
然后对于必须包含战士 (i) 实质是破环成链后,要能覆盖到 (i+m) ,所以我们只需要一直跳 (f[i]) ,步数就是答案....那么跳法非常神奇,我们可以连边 ((f[i],i)) ,那么就形成了一颗树,这样其实就是跳 (fa[i]) 直到 某个祖先 (i+m),这个就是老套路了,用一个栈维护即可,另外要注意答案相差不会超过 (1) ,所以我们先暴力求出 (1) 到根的距离 (x) ,然后每一次答案从 (x-1) 枚举起就行了

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=800005;
int head[N],nxt[N],to[N],n,f[N],m,l[N],num=0,b[N],r[N],fa[N],ans=0;
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
int q[N],top=0,re[N];
void dfs(int x){
   int u;q[++top]=x;
   for(int i=ans;i;i++){
      if(top-i<1)break;
      if(q[top-i]>=x+m){
         re[x]=i;
         break;
      }
   }
   for(int i=head[x];i;i=nxt[i]){
      u=to[i];
      dfs(u);
   }
   top--;
}
void work()
{
   int x,y;
   scanf("%d%d",&n,&m);m=0;
   for(int i=1;i<=n;i++)
      scanf("%d%d",&l[i],&r[i]),b[++m]=l[i],b[++m]=r[i];
   sort(b+1,b+m+1);
   for(int i=1;i<=n;i++){
      l[i]=lower_bound(b+1,b+m+1,l[i])-b;
      r[i]=lower_bound(b+1,b+m+1,r[i])-b;
   }
   for(int i=1;i<=n;i++){
      x=l[i];y=r[i];
      if(x<y)f[x]=Max(f[x],y),f[x+m]=Max(f[x+m],y+m);
      else f[1]=Max(f[1],y),f[x]=Max(f[x],y+m),f[x+m]=Max(f[x+m],m+m);
   }
   for(int i=1;i<=m+m;i++)f[i]=Max(f[i],f[i-1]);
   for(int i=1;i<=m+m;i++)if(f[i]!=i)link(f[i],i),fa[i]=f[i];
   x=1;while(fa[x] && x<1+m)x=fa[x],ans++;ans--;
   dfs(m+m);
   for(int i=1;i<=n;i++)printf("%d ",re[l[i]]);
}

int main()
{
	work();
	return 0;
}

原文地址:https://www.cnblogs.com/Yuzao/p/7630095.html