洛谷 P2048 主席樹+區間修改
阿新 • • 發佈:2018-10-31
題目連結: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; }