洛谷 P2048 主席树+区间修改

版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/83246731

题目链接:https://www.luogu.org/problemnew/show/P2048

解题思路:

建立主席树对于第i颗线段树来说,区间(l,r)表示左端点是l-r的点,右端点是i的区间情况,对此第i颗线段树由i-1颗转移过来时只需要对当前线段树进行(1,i)区间都加上a[i]的值,那么这个操作就可以做区间更新,之后就是维护线段树区间最大值和位置就OK了.

然后先把i个最大值插入优先队列,i个最大值分别为第i个线段树的可选择的区间长度大小,即(i-R+1,i-L+1)中的最大值,假设在此区间中的最大值位置在m,取出之后将区间分裂为(i-R+1,m-1)和(m+1,i-L+1),对这两个区间还是可以用线段树求出最大值和位置,然后将这两个插入队列中即可,在队列中取出前k个元素就是前k大的区间和。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define lson l,mid
#define rson mid+1,r 
using namespace std;
typedef long long ll;
const int mx = 5e5 + 10;
const int mod = 1e9+7;
int n,m,L1,R1,root[mx];
int a[mx],add[mx*30],rs[mx*30];
int siz,ls[mx*30],d;
struct node
{
    int rt,l,r;
    int p,c;
    bool operator < (node A)const
    {
        return c < A.c;
    }
};
struct data
{
    int ps,Ma;
}s[mx*30];
priority_queue <node> st;
void build(int& rt,int l,int r)
{
    rt = siz++;
    if(l==r){
        s[rt].ps = l;
        return ;
    }
    int mid = (l+r)>>1;
    build(ls[rt],lson);
    build(rs[rt],rson);
}
data up(data a,data b)
{
    if(b.Ma>a.Ma) return b;
    return a;
}
void update(int x,int &y,int l,int r,int L,int R)
{
    y = siz++;
    s[y] = s[x],add[y] = add[x];
    ls[y] = ls[x],rs[y] = rs[x];
    if(L<=l&&r<=R){
        add[y] += d;
        s[y].Ma += d;
        return ;
    }
    int mid = (l+r)>>1;
    if(R<=mid) update(ls[x],ls[y],lson,L,R);
    else if(L>mid) update(rs[x],rs[y],rson,L,R);
    else{
        update(ls[x],ls[y],lson,L,mid);
        update(rs[x],rs[y],rson,mid+1,R);
    }
    s[y] = up(s[ls[y]],s[rs[y]]);
    s[y].Ma += add[y]; 
}
data query(int rt,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return s[rt];
    int mid = (l+r)>>1;
    data ans = {0,-inf};
    if(L<=mid) ans = up(ans,query(ls[rt],lson,L,R));
    if(R>mid) ans = up(ans,query(rs[rt],rson,L,R));
    return data{ans.ps,ans.Ma+add[rt]};
}
int main()
{ 
    scanf("%d%d%d%d",&n,&m,&L1,&R1);
    build(root[0],1,n);
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
        d = a[i];
        update(root[i-1],root[i],1,n,1,i);
        if(i>=L1){
            data ret = query(root[i],1,n,max(1,i-R1+1),i-L1+1);
            st.push(node{root[i],max(1,i-R1+1),i-L1+1,ret.ps,ret.Ma});
        }
    }
    ll ans = 0;
    data ret;
    while(m--){
        node now = st.top();
        st.pop();
        ans += now.c;
        if(now.p-now.l>0){
            ret = query(now.rt,1,n,now.l,now.p-1);
            st.push(node{now.rt,now.l,now.p-1,ret.ps,ret.Ma});
        }
        if(now.r-now.p>0){
            ret = query(now.rt,1,n,now.p+1,now.r);
            st.push(node{now.rt,now.p+1,now.r,ret.ps,ret.Ma});
        } 
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/83246731