scoi2015 bzoj4444 国旗计划

来源:互联网 发布:马踏棋盘贪心算法 编辑:程序博客网 时间:2024/05/18 00:10

http://www.lydsy.com/JudgeOnline/problem.php?id=4444


其实我并没想到正解~~

首先把环拆成链,两倍链。

然后要离散化

f[i]表示左端点在i之前的最多能覆盖到哪个位置

可以先处理f[i]在i的时候最多能覆盖到哪里,然后向前缀和一样搞一下。


暴力计算出1-m的最小次数L,所有人的最小人数和这个数之差的绝对值不会超过1. ----------------------这是一个性质,因为假设把1覆盖的区间拿走,一定会用1-2条覆盖缺口。再加入必须的一条,可能使0-2条变得无用。   但是综合一下,波动不会超过2,毕竟求1的时候是最优的,覆盖会尽可能大。


我们考虑一个点i,如果能求出最少用几次到i+m之后,答案就出来了。而这就是可以用f[]这样搞出来的.

最直接的做法就是暴力枚举每个点i,一直跳f[i],看最少用几次到i+m之后,但这个时间复杂度明显很高。


由于有性质,我们可以对于每个点的跳跃次数从L-1开始跳(前提是我们知道当前点跳L-1会到哪里,如果知道,就算是暴力也可以优化很多(波动不超过2,接近On了))


现在问题就转化成:求每个点跳L-1次会到达哪个点u,然后从u暴力枚举一直跳到i+1之后。


我们发现从i到f[i]有点类似于一个链接(链表),假设每个i到f[i]建了一条边,构成森林。      我们会发现,不管从哪个点出发,最后都会到达2m.

也就是说,如果我们把整棵树倒过来,他就是一棵以2m为根的树。

然后我们dfs遍历整棵树,同时用栈维护从根到当前点u这条路径上的点(也就是它一直跳到2m的路径,然后对于每个点,就可以很快找到跳L-1次会到哪个点了,因为他要求的答案就在栈中。)


然后,就很好做了。

#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<queue>#include<cmath>using namespace std;const int maxn=400000+20;int n,m;int read(){int res=0;char c=getchar();for(;c<'0'||c>'9';c=getchar());for(;c>='0'&&c<='9';c=getchar())res=res*10+c-'0';return res;}struct edge{int v,next;}e[maxn<<1];int head[maxn<<1];int k;void add(int u,int v){if(u==v)return ;e[k].v=v;e[k].next=head[u];head[u]=k++;}int det[maxn<<1];int a[maxn][2];int cnt,len,L;int st[maxn];int f[maxn<<1];//从i最多能到j int sta[maxn<<1];int ans[maxn];int top;int find(int x){return lower_bound(det+1,det+len+1,x)-det;}void dfs(int u){sta[++top]=u;if(u<=m)for(int i=L;;i++)if(sta[top-i]>=u+m){ans[u]=i;break;}for(int i=head[u];~i;i=e[i].next)dfs(e[i].v);top--;}int main(){memset(head,-1,sizeof(head));k=0;cnt=0;n=read(),m=read();for(int i=1;i<=n;i++){a[i][0]=read();a[i][1]=read();det[++cnt]=a[i][0];det[++cnt]=a[i][1];}sort(det+1,det+cnt+1);len=unique(det+1,det+cnt+1)-det-1;m=len;for(int i=1;i<=n;i++){int x=find(a[i][0]),y=find(a[i][1]);st[i]=x;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],2*m);}}for(int i=1;i<=2*m;i++)f[i]=max(f[i],f[i-1]);//维护前缀 L=-1;top=0;for(int i=1;i<=m;i=f[i])L++;for(int i=1;i<=2*m;i++)add(f[i],i);dfs(2*m);for(int i=1;i<=n;i++)printf("%d ",ans[st[i]]);return 0;}



0 0
原创粉丝点击