[BJOI2017]喷式水战改

= = 虽然这题并不太难调 可我还是调了一年呀。。
一个区间DP+平衡树维护。因为空间不太够,所以点合并起来(就像NOIP2017列队一样)。
然后用的时候拆开,最多2e5个点。

考虑状态 f[l][r][i][j] f [ l ] [ r ] [ i ] [ j ] 为l-r区间内用了从i到j的方案的最大价值。转移显然。。然后就在平衡树上调就好了= =然后你要注意update时不要写反,拆点时尽量不要递归。。别写错点的标号等等等等错误。。。

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define mp make_pair
typedef pair<ll,ll>par;
const ll MAXN=5e5+5;

struct data{
    ll f[4][4]; 
    ll getans(){
        ll ans=0;
        for(ll i=0;i<=3;i++){
            for(ll j=i;j<=3;j++){
                ans=max(ans,f[i][j]);
            }
        }
        return ans;
    }
};
data operator + (data a,data b){
    data c;
    for(ll i=0;i<=3;i++){
        for(ll j=i;j<=3;j++){
            c.f[i][j]=0;
            for(ll k=i;k<=j;k++){
            //  cout<<a.f[i][k]<<" "<<i<<":"<<j<<":"<<k<<endl;
                c.f[i][j]=max(a.f[i][k]+b.f[k][j],c.f[i][j]);
            }   
        }
    }
    return c;
}

struct Treap{
    ll size[MAXN],prio[MAXN],lson[MAXN],rson[MAXN],ai[MAXN],bi[MAXN],ci[MAXN],si[MAXN],rt,cnt;
    data d[MAXN],g[MAXN];
    inline void pushup(ll o){
        ll l=lson[o],r=rson[o];
        size[o]=size[l]+size[r]+si[o];
        g[o]=d[o];
        if(l)g[o]=g[l]+g[o];
        if(r)g[o]=g[o]+g[r];
    }
    inline ll newnode(ll a,ll b,ll c,ll num){
        ++cnt;
        size[cnt]=num;prio[cnt]=rand();lson[cnt]=rson[cnt]=0;
        ai[cnt]=a,bi[cnt]=b,ci[cnt]=c;si[cnt]=num;
        d[cnt].f[0][0]=d[cnt].f[3][3]=a*num;
        d[cnt].f[1][1]=b*num;d[cnt].f[2][2]=c*num;
        for(ll i=0;i<=3;i++){
            for(ll j=i+1;j<=3;j++){
                d[cnt].f[i][j]=max(d[cnt].f[i][j-1],d[cnt].f[j][j]);
            }
        }
        return cnt;
    }
    ll merge(ll x,ll y){
        if(!x){pushup(y);return y;}
        if(!y){pushup(x);return x;}
        if(prio[x]<prio[y]){
            rson[x]=merge(rson[x],y);pushup(x);return x;
        }
        lson[y]=merge(x,lson[y]);pushup(y);return y;
    }
    par split(ll p,ll x){
        if(!x)return mp(0,p);
        ll l=lson[p],r=rson[p];
        if(x<=size[l]){
            par tem=split(l,x);
            lson[p]=tem.second;pushup(p);return mp(tem.first,p);
        }
        else if(x>=size[l]+si[p]){
            par tem=split(r,x-size[l]-si[p]);
            rson[p]=tem.first;pushup(p);return mp(p,tem.second);
        }
        //par tem=split(l,size[l]);
        //par tem2=split(r,size[p]-size[l]-si[p]);
        //ll p1=newnode(ai[p],bi[p],ci[p],x-size[l]);
       // ll p2=newnode(ai[p],bi[p],ci[p],si[p]-x+size[l]);
        ll pre=si[p];si[p]=x-size[l];
        d[p].f[0][0]=d[p].f[3][3]=ai[p]*si[p];
        d[p].f[1][1]=bi[p]*si[p];d[p].f[2][2]=ci[p]*si[p];
        for(ll i=0;i<=3;i++){
            for(ll j=i+1;j<=3;j++){
                d[p].f[i][j]=max(d[p].f[i][j-1],d[p].f[j][j]);
            }
        }
        ll p1=newnode(ai[p],bi[p],ci[p],pre-si[p]);p1=merge(p1,r);rson[p]=0;
        pushup(p);pushup(p1);
        //cout<<p1<<":"<<endl;
        return mp(p,p1);
    }
    void insert(ll p,ll a,ll b,ll c,ll x){
        par tem=split(rt,p);
        ll dq=newnode(a,b,c,x);
        ll t=merge(tem.first,dq);
        rt=merge(t,tem.second);
    //  cout<<rt<<":";debug(rt);

    }

    void debug(ll p){
        if(lson[p])debug(lson[p]);
        cout<<p<<" "<<ai[p]<<endl;
        if(rson[p])debug(rson[p]);
    }
}T;


int main(){
//  freopen("amane.in","r",stdin);
//  freopen("amane.out","w",stdout);
    srand(19260817);
    ll n;
    scanf("%lld",&n);
    ll Now=0,Last=0;
    ll t1,t2,t3,t4,t5;
    scanf("%lld%lld%lld%lld%lld",&t1,&t2,&t3,&t4,&t5);
    T.rt=T.newnode(t2,t3,t4,t5);
    Last=T.d[T.rt].getans();
    printf("%lld\n",Last);

    for(ll i=2;i<=n;i++){
        ll t1,t2,t3,t4,t5;
        scanf("%lld%lld%lld%lld%lld",&t1,&t2,&t3,&t4,&t5);
        T.insert(t1,t2,t3,t4,t5);
        Now=T.g[T.rt].f[0][3];
        //cout<<Now<<"sas"<<endl;
        printf("%lld\n",Now-Last);
        Last=Now;
    }
    return 0;
}
/*
5
0 25 37 46 2
1 32 14 16 3
3 99 77 88 4
2 43 68 57 5
14 72 36 18 6
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值