首页 > 代码库 > Codeforces Round #262 (Div. 2)C(二分答案,延迟标记)

Codeforces Round #262 (Div. 2)C(二分答案,延迟标记)

这是最大化最小值的一类问题,这类问题通常用二分法枚举答案就行了。

二分答案时,先确定答案肯定在哪个区间内。然后二分判断,关键在于怎么判断每次枚举的这个答案行不行。

我是用a[i]数组表示初始时花的高度,b[i]表示要达到当前枚举的答案(即mid的值)需要这朵花再涨多少。这两个数组很好算,关键是一次浇连续的w朵花,如何更新区间(暴力的O(n2)的去更新就超时了)?可以用线段树,但是这道题没有涉及区间查询,就是在一个数组上更新区间,用线段树未免小题大做。那么其实这种更新就用延迟标记的思想(懒操作)就可以O(n)的解决了。具体方法参见这道很裸的题:hdu4970

lazy[]这个标记数组的作用其实就是能记录更新区间到哪里停止.

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<map>#include<set>#include<vector>#include<algorithm>#include<stack>#include<queue>using namespace std;#define INF 1000000000#define eps 1e-8#define pii pair<int,int>#define LL long long intconst int maxn=110009;int n,m,w,a[maxn],b[maxn],lazy[maxn],ans=0;/*lazy[]这个标记数组的作用其实就是能记录更新区间到哪里停止*/int main(){    //freopen("in6.txt","r",stdin);    scanf("%d%d%d",&n,&m,&w);    for(int i=1; i<=n; i++)    {        scanf("%d",&a[i]);    }    int l=1,r=maxn+INF,mid;    while(l<=r)    {        memset(lazy,0,sizeof(lazy));        mid=(r+l)/2;        for(int i=1; i<=n; i++) b[i]=max(0,mid-a[i]);        int tm=m,x=0;        for(int i=1;i<=n;i++)//开始浇水        {            x+=lazy[i];//要先看这一步是不是有标记            b[i]-=x;//把前面对影响到当前b[i]的浇水操作浇上            if(b[i]>0)//还大于0,那么就必须要从它开始再来一段浇水了            {                tm-=b[i];                if(tm<0) break;//天数限制到了                lazy[i+w]-=b[i];                x+=b[i];            }        }        if(tm<0) r=mid-1;        else        {            ans=mid;            l=mid+1;        }    }    printf("%d\n",ans);}

 

Codeforces Round #262 (Div. 2)C(二分答案,延迟标记)