• bzoj4504 K个串


    这个题咕了快一年了。。。。。

    其实并不难

    题目很苟,就是子串的和定义为数字和(出现多次算一次)

    连续子段、第k大?

    我们想起了NOI2010]超级钢琴

    如何快速查询下一个最大值?

    以r为结尾统计,主席树维护l位置答案!

     

    1.n棵主席树。第r个主席树,每个叶子结点li维护 li~r的和。其他节点维护子树的和的mx
    到r+1时,区间[las[a[r+1],r+1]加上a[r+1],这些区间和增加了(数颜色套路)。再前面的li,因为a[r+1]出现过了,就不算了。
    至于区间和,必须标记永久化。
    (mx=max(mxls,mxrs)+lasz[x] 查询的时候,一路上统计laz和,回溯的时候减去)
    (这样才能保证不影响以前版本的主席树)

    2.将每棵主席树中的最大值加入大根堆,第一个就是最大的子段和。
    大根堆每个节点是一个五元组:(r,l,L,R,sum) 表示,是一个l~r(第r棵主席树来的)的后缀,是L~R区间内的最大值,最大值是sum
    大根堆的排序标准就是sum值

    取出最大的五元组,拆成两半:
    (r,l',L,l-1,sum')和(r,l'',l+1,R,sum'')
    l',l'',分别用r的主席树logn求出最大值的位置。
    把这两个五元组加入大根堆。由于拆成左右两半,一定包含了r的次大子段和。不会漏记答案。

    3.循环第2步,直到凑够前k个为止。

     

    主席树标记永久化说一下:

    新节点直接继承原来节点的add,到了包含位置+=c

    mx维护子树所有位置的最大值(标记仅限于到x的路径上的(包括x))

    查询时候一路上的tag加上

    细节:

    空节点有意义。mx就是0,id是区间左端点。query时候特判。

    为了方便可以先build一棵空树

    不能对pair重载小于号??不知为啥

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mid ((l+r)>>1)
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=100000+5;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    int n,k;
    int a[N];
    struct node{
        int ls,rs;
        ll mx,ad;
        int id;
    }t[N*80];
    int tot;
    int rt[N];
    map<int,int>las;
    void pushup(int x){
        if(t[t[x].ls].mx>t[t[x].rs].mx) t[x].id=t[t[x].ls].id,t[x].mx=t[t[x].ls].mx+t[x].ad;
        else t[x].id=t[t[x].rs].id,t[x].mx=t[t[x].rs].mx+t[x].ad;
    }
    void build(int &x,int l,int r){
        x=++tot;
        if(l==r){
            t[x].id=l;return;
        }
        t[x].mx=0;
        t[x].id=l;//warning!!!! 
        build(t[x].ls,l,mid);build(t[x].rs,mid+1,r);
    }
    void upda(int &x,int y,int l,int r,int L,int R,int c){//add
    //    cout<<" upda "<<l<<" "<<r<<" || "<<L<<" "<<R<<" : "<<c<<endl;
        x=++tot;
        t[x].ad=t[y].ad;
        t[x].ls=t[y].ls;
        t[x].rs=t[y].rs;
        if(L<=l&&r<=R){
            t[x].mx=t[y].mx+c,t[x].id=t[y].id;
    //        else t[x].mx=c,t[x].id=l;//warning!!!
            t[x].ad+=c;
            return;
        }
        if(L<=mid&&mid<R){
            upda(t[x].ls,t[y].ls,l,mid,L,R,c);
            upda(t[x].rs,t[y].rs,mid+1,r,L,R,c);
        }else if(L<=mid){
            upda(t[x].ls,t[y].ls,l,mid,L,R,c);
        }else{
            upda(t[x].rs,t[y].rs,mid+1,r,L,R,c);
        }
        pushup(x);
    }
    pair<int,ll>cmp(pair<int,ll>a,pair<int,ll>b){
        if(a.se<b.se) return b;
        return a;
    }
    pair<int,ll>query(int x,int l,int r,int L,int R,ll tag){
        if(L<=l&&r<=R){
            if(x) return mk(t[x].id,t[x].mx+tag);
            else return mk(l,tag);
        }
        pair<int,ll>ret;ret.fi=0;ret.se=-inf;
        if(L<=mid) ret=cmp(ret,query(t[x].ls,l,mid,L,R,tag+t[x].ad));
        if(mid<R) ret=cmp(ret,query(t[x].rs,mid+1,r,L,R,tag+t[x].ad));
        return ret;
    }
    struct po{
        int pos,from;
        int L,R;
        ll sum;
        po(int p,int f,int l,int r,ll s){
            pos=p;from=f;L=l;R=r;sum=s;
        }
        bool friend operator <(po a,po b){
            return a.sum<b.sum;
        }
        void op(){
            cout<<" pos "<<pos<<" from "<<from<<endl;
            cout<<" L "<<L<<" R "<<R<<endl;
            cout<<" sum "<<sum<<endl;
        }
    };
    priority_queue<po>q;
    
    int main(){
        rd(n);rd(k);
        t[0].id=0;
    //    t[0].mx=-inf;
        for(reg i=1;i<=n;++i){
            rd(a[i]);
        }
        build(rt[0],1,n);
        for(reg i=1;i<=n;++i){
    //        cout<<" ii "<<i<<endl;
            upda(rt[i],rt[i-1],1,n,las[a[i]]+1,i,a[i]);
            las[a[i]]=i;
            pair<int,ll>pr=query(rt[i],1,n,1,i,0);
    //        cout<<" pr "<<pr.fi<<" "<<pr.se<<endl;
            q.push(po(pr.fi,i,1,i,pr.se));
        }
        ll ans=0;
        while(k--){
            po now=q.top();q.pop();
    //        now.op();
            ans=now.sum;
            pair<int,ll>pr;
            if(now.pos+1<=now.R){
                pr=query(rt[now.from],1,n,now.pos+1,now.R,0);
                q.push(po(pr.fi,now.from,now.pos+1,now.R,pr.se));
            }
            if(now.L<=now.pos-1){
                pr=query(rt[now.from],1,n,now.L,now.pos-1,0);
                q.push(po(pr.fi,now.from,now.L,now.pos-1,pr.se));
            }
        }
        printf("%lld",ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/15 17:20:13
    */
  • 相关阅读:
    Valid Parentheses
    3Sum
    泛型(一)
    Longest Common Prefix
    Roman to Integer
    Integer to Roman
    Container With Most Water
    知道创宇研发技能表v2.2
    anti-dns pinning 攻击
    dominator
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10539189.html
Copyright © 2020-2023  润新知