zoukankan      html  css  js  c++  java
  • bzoj 3267: KC采花&&3272&&3638&&3502 线段树

    题目大意

    给定一个长为n的序列,维护两种操作:
    1.单点修改
    2.在[l,r]这段区间中取k个互不相交的子段,使子段之和最大.
    (n leq 50000,k leq 20)

    题解

    四倍经验.(但我的写法太丑过不了3502)
    我们可以很简单地构建出一个最大费用最大流模型
    把每个点拆点,然后S,T分别连接即可
    但是这道题n达到50000,直接上费用流绝对T的不要不要的
    我们想一下这样费用流的时候都在干什么
    每次找出一个费用最大的区间...把答案加上费用之和...把所有的费用取反...
    我们发现我们可以用线段树维护这个过程!
    支持最大子段和查询和反转操作
    所以我们维护一个最大子段和和最小子段和即可!!
    啥?好像好要维护取到最大子段和和最小子段和时的端点?
    啥?要维护从左端点的开始的最大子段和和从右端点开始的最大子段和?
    好麻烦啊。。。估计是我写丑了...所以3502才被卡空间了...

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(int &x){
        x=0;char ch;bool flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
    inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
    const int maxn = 100010;
    const int inf = 0x3f3f3f3f;
    struct Node{
        int mx,lmx,rmx,lx,rx,plx,prx;
        int mn,lmn,rmn,ln,rn,pln,prn;
        int sum,rev;
        Node(){
            mx = lmx = rmx = -inf;
            mn = lmn = rmn =  inf;
            sum = lx = rx = ln = rn = rev = 0;
        }
        inline void set(int x,int p){
            rev = 0;mx = lmx = rmx = mn = lmn = rmn = sum = x;
            lx=rx=plx=prx=ln=rn=pln=prn = p;
        }
        inline void reve(){
            swap(mx,mn);swap(lmn,lmx);swap(rmn,rmx);
            swap(lx,ln);swap(rx,rn);swap(plx,pln);swap(prx,prn);
            mx = -mx;mn = -mn;
            lmn = -lmn;lmx = -lmx;
            rmx = -rmx;rmn = -rmn;
            sum = -sum;rev ^= 1;
        }
        Node friend operator + (const Node &l,const Node &r){
            Node c;
            c.sum = l.sum + r.sum;
            c.lmx = max(l.lmx,l.sum+max(r.lmx,0));
            c.rmx = max(r.rmx,r.sum+max(l.rmx,0));
            c.mx = max(max(l.mx,r.mx),max(l.rmx+max(0,r.lmx),max(l.rmx,0)+r.lmx) );
            if(c.lmx == l.lmx) c.plx = l.plx;
            else c.plx = r.plx;
            if(c.rmx == r.rmx) c.prx = r.prx;
            else c.prx = l.prx;
            if(c.mx == l.mx) c.lx = l.lx,c.rx = l.rx;
            else if(c.mx == r.mx) c.lx = r.lx,c.rx = r.rx;
            else if(c.mx == l.rmx+r.lmx)c.lx = l.prx,c.rx = r.plx;
            c.lmn = min(l.lmn,l.sum+min(r.lmn,0));
            c.rmn = min(r.rmn,r.sum+min(l.rmn,0));
            c.mn = min(min(l.mn,r.mn),min(l.rmn+min(0,r.lmn),min(l.rmn,0)+r.lmn) );
            if(c.lmn == l.lmn) c.pln = l.pln;
            else c.pln = r.pln;
            if(c.rmn == r.rmn) c.prn = r.prn;
            else c.prn = l.prn;
            if(c.mn == l.mn) c.ln = l.ln,c.rn = l.rn;
            else if(c.mn == r.mn) c.ln = r.ln,c.rn = r.rn;
            else if(c.mn == l.rmn+r.lmn) c.ln = l.prn,c.rn = r.pln;
        }
    }T[maxn<<2];
    int a[maxn];
    inline void pushdown(int rt,int l,int r){
        if(T[rt].rev == 0) return;
        T[rt].rev = 0;
        if(l == r) return;
        T[rt<<1].reve();T[rt<<1|1].reve();
    }
    void build(int rt,int l,int r){
        if(l == r){
            T[rt].set(a[l],l);
            return;
        }int mid = l+r >> 1;
        build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
        T[rt] = T[rt<<1] + T[rt<<1|1];
    }
    void modify(int rt,int l,int r,int pos,int val){
        if(l == r){
            T[rt].set(val,l);
            return;
        }
        int mid = l+r >> 1;
        pushdown(rt,l,r);
        if(pos <= mid) modify(rt<<1,l,mid,pos,val);
        else modify(rt<<1|1,mid+1,r,pos,val);
        T[rt] = T[rt<<1] + T[rt<<1|1];
    }
    Node query(int rt,int l,int r,int L,int R){
        if(L <= l && r <= R) return T[rt];
        int mid = l+r >> 1;
        pushdown(rt,l,r);
        if(R <= mid) return query(rt<<1,l,mid,L,R);
        if(L >  mid) return query(rt<<1|1,mid+1,r,L,R);
        return query(rt<<1,l,mid,L,R) + query(rt<<1|1,mid+1,r,L,R);
    }
    void rever(int rt,int l,int r,int L,int R){
        if(L <= l && r <= R){T[rt].reve();return;}
        int mid = l+r >> 1;
        pushdown(rt,l,r);
        if(L <= mid) rever(rt<<1,l,mid,L,R);
        if(R >  mid) rever(rt<<1|1,mid+1,r,L,R);
        T[rt] = T[rt<<1] +  T[rt<<1|1];
    }
    struct seg{
        int l,r;
        seg(int l=0,int r=0){this->l=l;this->r=r;}
    }sta[22];
    int top,n;
    inline int spfa(int l,int r,int num){
        top = 0;int ret = 0;
        while(num--){
            Node x = query(1,1,n,l,r);
            if(x.mx < 0) break;
            sta[++top] = seg(x.lx,x.rx);
            ret += x.mx;
            rever(1,1,n,x.lx,x.rx);
        }
        while(top){
            rever(1,1,n,sta[top].l,sta[top].r);
            --top;
        }
        return ret;
    }
    int main(){
        read(n);
        for(int i=1;i<=n;++i) read(a[i]);
        build(1,1,n);
        int m;read(m);
        int op,l,r,k;
        while(m--){
            read(op);read(l);read(r);
            if(op == 0){
                modify(1,1,n,l,r);
            }else{
                read(k);
                printf("%d
    ",spfa(l,r,k));
            }
        }
        getchar();getchar();
        return 0;
    }
    
  • 相关阅读:
    工作感悟(一)
    laydate组件选择时间段的判断
    Win10下免安装版JDK8环境变量配置
    IDEA中lombok插件的安装
    解决加载WEB页面时,由于JS文件引用过多影响页面打开速度的问题
    Windows环境下的MYSQL5.7配置文件定位
    MYSQL使用source命令,导入SQL文件
    MYSQL5.7生成列简介及创建
    MYSQL慢查询优化方法及优化原则
    批量提取文件夹下所有目录及文件名称
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6414073.html
Copyright © 2011-2022 走看看