bzoj4172: 弹珠


思路:先用splay处理出弹珠序列,然后就是斜率优化了

首先有f[i]=-a[i]*p[j]+q[j]

稍微变形得q[j]=a[i]*p[j]+f[i]

用单调栈维护上凸壳,询问时二分,然后就没有然后了。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) a>b?a:b
#define ll long long
const int maxn=400010,inf=(int)1e9;
const double eps=1e-9;
using namespace std;
int n,m,a[maxn],cnt,top,q[maxn];ll f[maxn];char op[10],ch;
struct node{ll x,y;}p[maxn];
void read(int &x){
    for (ch=getchar();!isdigit(ch);ch=getchar());
    for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());   
}
struct Spy{
    int fa[maxn],c[maxn][2],size[maxn],val[maxn],root,tot;
    int newnode(int v){val[++tot]=v,size[tot]=1,fa[tot]=c[tot][0]=c[tot][1]=0;return tot;}
    void clear(){tot=c[1][1]=size[1]=2,root=fa[2]=size[2]=1;}
    int which(int x){return c[fa[x]][1]==x;}
    void update(int x){size[x]=size[c[x][0]]+size[c[x][1]]+1;}
    void rotate(int x){
        int y=fa[x],z=fa[y],nx=which(x),ny=which(y);
        fa[c[x][!nx]]=y,c[y][nx]=c[x][!nx];
        fa[x]=z;if (z) c[z][ny]=x;
        fa[y]=x,c[x][!nx]=y;update(y);
    }
    void splay(int x){
        while (fa[x]){
            if (!fa[fa[x]]) rotate(x);
            else if (which(fa[x])==which(x)) rotate(fa[x]),rotate(x);
            else rotate(x),rotate(x);
        }
        root=x,update(x);
    }
    int getpos(int rank){
        for (int x=root;;){
            //printf("rank%d %d %d %d\n",rank,size[root],size[c[root][0]],size[c[root][1]]);
            if (rank<size[c[x][0]]+1) x=c[x][0];
            else if (rank==size[c[x][0]]+1) return x;
            else rank-=(size[c[x][0]]+1),x=c[x][1];
        }
    }
    void modify(int rank,int v){int x=getpos(rank);val[x]=v,splay(x);}
    void insert(int rank,int v){
        int x=getpos(rank);splay(x);
        int xx=c[x][1];for (;c[xx][0];xx=c[xx][0]) ;
        c[xx][0]=newnode(v),fa[tot]=xx,splay(tot);
    }
    void get(int x){
        if (c[x][0]) get(c[x][0]);
        if (x!=1&&x!=2) a[++cnt]=val[x];
        if (c[x][1]) get(c[x][1]);
    }
}T;
 
double slope(int i,int j){
    if (i==0||j==0) return inf;  
    if (i==inf||j==inf) return -inf;  
    return 1.0*(p[i].y-p[j].y)/(double)(p[i].x-p[j].x);
}
 
void work(){
    q[0]=0,q[top=1]=1,q[top+1]=inf;
    for (int i=2;i<=n;i++){
        int l=1,r=top,mid=(l+r)>>1;
        while (1){
            if (slope(q[mid-1],q[mid])+eps>=a[i]&&slope(q[mid],q[mid+1])<=eps+a[i]){break;}
            if (slope(q[mid],q[mid+1])>eps+a[i]) l=mid+1;
            else r=mid-1;
            mid=(l+r)>>1;
        }
        f[i]=-p[q[mid]].x*a[i]+p[q[mid]].y;
        while (top>1&&slope(q[top-1],q[top])<slope(q[top],i)) --top;
        q[++top]=i;q[top+1]=inf;
    }
    for (int i=2;i<=n;i++) printf("%lld\n",max(0,f[i]));
}
 
int main(){
    scanf("%d%d",&n,&m),T.clear();
    for (int i=1,x,y;i<=m;i++){
        scanf("%s",op);read(x),read(y);
        if (op[0]=='I') T.insert(x+1,y);
        else T.modify(x+2,y);
    }
    T.get(T.root);
    //for (int i=1;i<=cnt;i++) printf("%d\n",a[i]);
    for (int i=1,x,y;i<=n;i++) read(x),read(y),p[i].x=x,p[i].y=y;
    work();
    return 0;
}


posted @ 2015-07-11 15:51  orzpps  阅读(150)  评论(0编辑  收藏  举报