bzoj3272 Zgg吃东西

题目描述:

bz

题解:

线段树模拟费用流。

想法和种树有点类似。

每次取区间内权值和最大的一段,然后整体乘$-1$,代表再次选中时会去掉之前的影响。

线段树维护一堆东西……

小白逛公园双倍快乐。乘$-1$时交换正反。

[滑稽]

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,m;
int chg[50][2];
struct n_8
{
    int w,wl,wr,wu,pl,pr,pll,prr;
    n_8(){}
    n_8(int w,int wl,int wr,int wu,int pl,int pr,int pll,int prr):w(w),wl(wl),wr(wr),wu(wu),pl(pl),pr(pr),pll(pll),prr(prr){}
};
void chkmax(int&a,int&b,int c,int d,int e,int f)
{
    if(c>e)a=c,b=d;
    else a=e,b=f;
}
void chkmax(int&a,int&b,int&c,int d,int e,int f,int g,int h,int i)
{
    if(d>g)a=d,b=e,c=f;
    else a=g,b=h,c=i;
}
void chkmin(int&a,int&b,int c,int d,int e,int f)
{
    if(c<e)a=c,b=d;
    else a=e,b=f;
}
void chkmin(int&a,int&b,int&c,int d,int e,int f,int g,int h,int i)
{
    if(d<g)a=d,b=e,c=f;
    else a=g,b=h,c=i;
}
void Swap(int&a,int&b)
{
    swap(a,b);
    a=-a,b=-b;
}
n_8 operator + (n_8 a,n_8 b)
{
    n_8 c;
    c.w = a.w+b.w;
    chkmax(c.wl,c.pll,a.wl,a.pll,a.w+b.wl,b.pll);
    chkmax(c.wr,c.prr,b.wr,b.prr,b.w+a.wr,a.prr);
    chkmax(c.wu,c.pl,c.pr,a.wu,a.pl,a.pr,b.wu,b.pl,b.pr);
    chkmax(c.wu,c.pl,c.pr,c.wu,c.pl,c.pr,a.wr+b.wl,a.prr,b.pll);
    return c;
}
struct segtree
{
    int w[N<<2],wl[N<<2],wr[N<<2],wu[N<<2],pl[N<<2],pr[N<<2],pll[N<<2],prr[N<<2];
    int _wl[N<<2],_wr[N<<2],_wu[N<<2],_pl[N<<2],_pr[N<<2],_pll[N<<2],_prr[N<<2];
    bool res[N<<2];
    void update(int u)
    {
        w[u] = w[u<<1]+w[u<<1|1];
        chkmax(wl[u],pll[u],wl[u<<1],pll[u<<1],w[u<<1]+wl[u<<1|1],pll[u<<1|1]);
        chkmax(wr[u],prr[u],wr[u<<1|1],prr[u<<1|1],w[u<<1|1]+wr[u<<1],prr[u<<1]);
        chkmin(_wl[u],_pll[u],_wl[u<<1],_pll[u<<1],w[u<<1]+_wl[u<<1|1],_pll[u<<1|1]);
        chkmin(_wr[u],_prr[u],_wr[u<<1|1],_prr[u<<1|1],w[u<<1|1]+_wr[u<<1],_prr[u<<1]);
        chkmax(wu[u],pl[u],pr[u],wu[u<<1],pl[u<<1],pr[u<<1],wu[u<<1|1],pl[u<<1|1],pr[u<<1|1]);
        chkmax(wu[u],pl[u],pr[u],wu[u],pl[u],pr[u],wr[u<<1]+wl[u<<1|1],prr[u<<1],pll[u<<1|1]);
        chkmin(_wu[u],_pl[u],_pr[u],_wu[u<<1],_pl[u<<1],_pr[u<<1],_wu[u<<1|1],_pl[u<<1|1],_pr[u<<1|1]);
        chkmin(_wu[u],_pl[u],_pr[u],_wu[u],_pl[u],_pr[u],_wr[u<<1]+_wl[u<<1|1],_prr[u<<1],_pll[u<<1|1]);
    }
    void reser(int u)
    {
        res[u]^=1;
        w[u] = -w[u];
        Swap(wl[u],_wl[u]);Swap(wr[u],_wr[u]);Swap(wu[u],_wu[u]);
        swap(pl[u],_pl[u]);swap(pr[u],_pr[u]);
        swap(pll[u],_pll[u]);swap(prr[u],_prr[u]);
    }
    void pushdown(int u)
    {
        if(res[u])
        {
            reser(u<<1);
            reser(u<<1|1);
            res[u] = 0;
        }
    }
    void build(int l,int r,int u)
    {
        if(l==r)
        {
            int x;read(x);
            w[u] = wu[u] = _wu[u] = wl[u] = _wl[u] = wr[u] = _wr[u] = x;
            pl[u]=pr[u]=pll[u]=prr[u]=_pl[u]=_pr[u]=_pll[u]=_prr[u]=l;
            return ;
        }
        int mid = (l+r)>>1;
        build(l,mid,u<<1);
        build(mid+1,r,u<<1|1);
        update(u);
    }
    void insert(int l,int r,int u,int qx,int d)
    {
        if(l==r)
        {
            w[u] = wu[u] = _wu[u] = wl[u] = _wl[u] = wr[u] = _wr[u] = d;
            return ;
        }
        pushdown(u);
        int mid = (l+r)>>1;
        if(qx<=mid)insert(l,mid,u<<1,qx,d);
        else insert(mid+1,r,u<<1|1,qx,d);
        update(u);
    }
    void erase(int l,int r,int u,int ql,int qr)
    {
        if(l==ql&&r==qr)
        {
            reser(u);
            return ;
        }
        pushdown(u);
        int mid = (l+r)>>1;
        if(qr<=mid)erase(l,mid,u<<1,ql,qr);
        else if(ql>mid)erase(mid+1,r,u<<1|1,ql,qr);
        else erase(l,mid,u<<1,ql,mid),erase(mid+1,r,u<<1|1,mid+1,qr);
        update(u);
    }
    n_8 query(int l,int r,int u,int ql,int qr)
    {
        if(l==ql&&r==qr)return n_8(w[u],wl[u],wr[u],wu[u],pl[u],pr[u],pll[u],prr[u]);
        pushdown(u);
        int mid = (l+r)>>1;
        if(qr<=mid)return query(l,mid,u<<1,ql,qr);
        else if(ql>mid)return query(mid+1,r,u<<1|1,ql,qr);
        else return query(l,mid,u<<1,ql,mid)+query(mid+1,r,u<<1|1,mid+1,qr);
    }
}tr;
int main()
{
    read(n);
    tr.build(1,n,1);
    read(m);
    int op,x,y,w;
    for(int i=1;i<=m;i++)
    {
        read(op),read(x),read(y);
        if(!op)tr.insert(1,n,1,x,y);
        else
        {
            read(w);
            n_8 tmp = tr.query(1,n,1,x,y);
            int ans = 0;
            for(int j=1;j<=w;j++)
            {
                if(tmp.wu>0)
                {
                    ans+=tmp.wu;
                    chg[j][0]=tmp.pl,chg[j][1]=tmp.pr;
                    tr.erase(1,n,1,tmp.pl,tmp.pr);
                    tmp = tr.query(1,n,1,x,y);
                }else
                {
                    w = j-1;
                    break;
                }
            }
            printf("%d\n",ans);
            for(int j=1;j<=w;j++)
                tr.erase(1,n,1,chg[j][0],chg[j][1]);
        }
    }
    return 0;
}
View Code

压行大法好。

posted @ 2019-04-24 16:33  LiGuanlin  阅读(234)  评论(0编辑  收藏  举报