测试51T2:单调栈维护下凸包二分

单调栈维护凸包,并在凸包上二分的一类题。

1、本题维护的每个决策点是一个一次函数,即一条线。

2、下凸包的维护:1、斜率递增,pop掉斜率比他大的
                    2、交点递减,防止不优的线影响决策

3、代码自己写的,开始没看std,改不出来后看了第二个while,即交点递减,没考虑到。

这点比较好。要相信自己也能写出来。

详细见注释。

#include<bits/stdc++.h>
#define F(i,a,b) for(rg int i=a;i<=b;++i)
#define rg register
#define LL long long
#define il inline
#define pf(a) printf("%lld ",a)
#define phn puts("")
using namespace std;
#define int LL 
#define N 500010
int read();
int n,que;
int s[N],a[N],c[N];
int min(int x,int y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
struct Q{
    int x,y,id;
    friend bool operator <(const Q& a,const Q& b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
}b[N];
int sta[N],top,ans[N];
double get(int i,int j){
    return 1.0*(c[j]-c[i])/(a[i]-a[j]);
}
void push(int x){
    while(top&&a[sta[top]]>=a[x])--top;
    while(top>1&&get(x,sta[top])>=get(sta[top],sta[top-1]))--top;
    /** 这里是凸包的维护。第二句:使交点在栈内单调递减。因为画图发现交点递减才成为凸包,否则上一条线可以去掉
    如果不去掉,决策会使用上一条线,导致挡住原本更优的决策
    所以下凸包的维护:1、斜率递增,pop掉斜率比他大的
              2、交点递减,防止不优的线影响决策
    */
    sta[++top]=x;
}
/** 可以证明,超过边界的不合法的决策点不优*/
int solve(int x,int y){
    int l=1,r=top,mid;
    while(l<r){
        mid=l+r>>1;
    //    if(y-sta[mid]+1>x){l=mid+1;continue;}
        if(get(sta[mid],sta[mid+1])>x-y)l=mid+1;
        else r=mid;
    }    
    l=sta[l];
//    pf(l);pf(x);pf(y);phn;
    /*if(x==100&&y==7){
        F(i,1,top)pf(a[sta[i]]);phn;while(1);
    }*/
    return s[y]-s[l]+(x-y+l)*a[l];
}
signed main(){
//    freopen("function2.in","r",stdin);    freopen("1.out","w",stdout);
    n=read(); F(i,1,n)s[i]=s[i-1]+(a[i]=read()),c[i]=i*a[i]-s[i];
    que=read(); F(i,1,que)b[i]=(Q){read(),read(),i};
    sort(b+1,b+que+1);
    int p=1;
    while(b[p].y==1){
        ans[b[p].id]=a[1]*b[p].x;++p;
    }    
    sta[top=1]=1;
    /**     s[y]0-s[i]+(x-y+i)*a[i] 
        先判两个端点。
    */
    int i,x,y;
    F(k,2,n){    
        push(k);
        if(top==1){
            i=sta[1];
            while(b[p].y==k){
                ans[b[p].id]=a[k]*b[p].x;
                ++p;
            }
            continue;
        }
        while(b[p].y==k){
            ans[b[p].id]=solve(b[p].x,k);
            ++p;
        }
    //    push(k);
    }    
    F(i,1,que)printf("%lld\n",ans[i]);
}
int read(){
    int s=0,f=0;char ch;
    while(ch=getchar(),ch=='-'?f=1:0,!isdigit(ch));
    for(;isdigit(ch);s=s*10+(ch^48),ch=getchar());
    return f?-s:s;
}
/*
g++ 1.cpp -g
./a.out
g++ dp.cpp -g
./a.out
10
10 9 1 7 4 6 8 5 2 3
10
4 2
100 2
6 3
1 4
3 5
1 7
100 7 
5 8
2 9
100 10
*/
View Code

 关于不合法的点一定不优的证明:

我证出来了,但是懒得写了。我要去看T3了。

posted @ 2019-09-26 12:20  seamtn  阅读(231)  评论(0编辑  收藏  举报