1. 程式人生 > >[NOI2010]超級鋼琴 - 主席樹 - 堆

[NOI2010]超級鋼琴 - 主席樹 - 堆

題目大意:問長度在[L,R]的前k大子區間的和。5e5。
題解:對每個右端點用主席樹維護其第k大即可,然後光榮MLE。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second #define INF 2000000000 #define N 500010 #define S(rt) (((rt)==NULL)?0:(rt)->s) #define CH(rt,g) (((rt)==NULL)?NULL:(rt)->ch[g]) #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; typedef pair<int,int> pii; typedef
set<int>::iterator sit; inline int inn() { int x=0,s=1,ch;while(((ch=gc)<'0'||ch>'9')&&ch!='-'); if(ch^'-') x=ch^'0';else s=-1; while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0'); return s*x; } struct segment{ int s;segment *ch[2]; }*T[N];priority_queue<
pii> q;int a[N],s[N],st[N],ed[N],cnt[N]; int build(segment* &x,segment *y,int l,int r,int p) { x=new segment,x->s=S(y)+1; x->ch[0]=CH(y,0),x->ch[1]=CH(y,1); int mid=(l+r)>>1;if(l==r) return 0; if(p<=mid) build(x->ch[0],CH(y,0),l,mid,p); if(mid<p) build(x->ch[1],CH(y,1),mid+1,r,p); return 0; } int query(segment *x,segment *y,int l,int r,int k) { if(S(x)-S(y)<k) return INF;int mid=(l+r)>>1,v;if(l==r) return l; if(k<=(v=S(CH(x,0))-S(CH(y,0)))) return query(CH(x,0),CH(y,0),l,mid,k); return query(CH(x,1),CH(y,1),mid+1,r,k-v); } inline int query(int s,int t,int c,int mx) { if(s>t) return INF;return query(T[t],s?T[s-1]:NULL,1,mx,c); } int main() { // freopen("data.in","r",stdin),freopen("std.out","w",stdout); int n=inn(),k=inn(),L=inn(),R=inn(),bas=1,mx=0;lint Ans=0ll; rep(i,1,n) a[i]=inn(),s[i]=s[i-1]+a[i],bas=max(bas,-s[i]+1),mx=max(mx,s[i]); mx+=bas;rep(i,0,n) s[i]+=bas,build(T[i],i?T[i-1]:NULL,1,mx,s[i]); rep(i,1,n) st[i]=max(i-R,0),ed[i]=i-L,cnt[i]=1,q.push(mp(s[i]-query(st[i],ed[i],1,mx),i)); for(int x;k;k--) x=q.top().sec,Ans+=q.top().fir,q.pop(),q.push(mp(s[x]-query(st[x],ed[x],++cnt[x],mx),x)); return !printf("%lld\n",Ans); }