这道题因为有一个数在序列中出现多次只算一次的限制。我们可以这样搞。假设在当前题意下求给定右端点的区间最值。那么我们可以预处理出每个数前一次出现的位置pre[i] 。接下来从左到右加入每一个值,就是在 pre[i] + 1 —— i 这个区间内加上 v[i] 的值,这样就可以得到以当前 i 点为右端点的各个区间的值(很明显维护一下最值就好了)。接下来很明显有n个版本的线段树(如果你说一开始那个空的线段树也算一个版本的话,就有n+1个),那就要用主席树动态开点。而取第K大值的操作有点像超级钢琴,不过在这里要维护5元组吧! 分别是 区间左端点, 区间右端点, 区间最值点, 区间最值, 线段树版本。 没了!就这样!
1 #include<cstdio> 2 #include<queue> 3 #include<iostream> 4 #include<map> 5 #define rep(i,j,k) for(register int i = j; i <= k; i++) 6 #define maxn 100005 7 #define ll long long 8 #define inf 1ll * 10000000 * 10000000 9 using namespace std; 10 11 inline int read() { 12 int s = 0, t = 1; char c = getchar(); 13 while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); } 14 while( isdigit(c) ) s = s * 10 + c - 48, c = getchar(); 15 return s * t; 16 } 17 18 int ql, qr, d, tot = 0, rot[maxn], c[maxn*100][2], pos[maxn*100]; ll sum[maxn*100], v[maxn*100]; 19 #define lc c[k][0] 20 #define rc c[k][1] 21 #define mid ((l+r)>>1) 22 inline void build(int l,int r,int &k) { 23 k = ++tot; pos[k] = l; 24 if( l == r ) return; 25 build(l,mid,lc); build(mid+1,r,rc); 26 } 27 inline void update(int &k,int pre,int l,int r) { 28 k = ++tot; 29 sum[k] = sum[pre], v[k] = v[pre]; 30 lc = c[pre][0], rc = c[pre][1]; 31 if( ql <= l && r <= qr ) { sum[k] += d; v[k] += d; pos[k] = pos[pre]; return; } 32 if( ql <= mid ) update(lc,c[pre][0],l,mid); else lc = c[pre][0]; 33 if( qr > mid ) update(rc,c[pre][1],mid+1,r); else rc = c[pre][1]; 34 if( sum[lc] > sum[rc] ) sum[k] = sum[lc] + v[k], pos[k] = pos[lc]; 35 else sum[k] = sum[rc] + v[k], pos[k] = pos[rc]; 36 } 37 38 int wh; ll maxl; 39 inline void querymx(int k,int l,int r, ll pd) { 40 if( ql <= l && r <= qr ) { 41 if( sum[k] + pd > maxl ) maxl = sum[k] + pd, wh = pos[k]; 42 return; 43 } 44 if( ql <= mid ) querymx(lc,l,mid,pd+v[k]); 45 if( qr > mid ) querymx(rc,mid+1,r,pd+v[k]); 46 } 47 48 inline void out(int k,int l,int r,ll pd) { 49 if( l == r ) { cout<<pd+sum[k]<<" "; return; } 50 out(lc,l,mid,pd+v[k]); out(rc,mid+1,r,pd+v[k]); 51 } 52 53 map<int,int> last; int pre[maxn], val[maxn]; 54 struct node{ int l, r, id, pos; ll v; bool operator < (const node&rhs) const { return v < rhs.v; }; }; 55 priority_queue<node> q; 56 #define mkp(i,j,k,l,d) (node){i,j,k,l,d} 57 int main() { 58 int n = read(), k = read(); 59 rep(i,1,n) val[i] = read(), pre[i] = last[val[i]], last[val[i]] = i;; 60 build(1,n,rot[0]); 61 rep(i,1,n) { 62 ql = pre[i] + 1, qr = i, d = val[i]; 63 update(rot[i],rot[i-1],1,n); 64 ql = 1, qr = i; maxl = -inf; 65 querymx(rot[i],1,n,0); 66 //out(rot[i],1,n,0); cout<<endl; 67 q.push(mkp(1,i,i,wh,maxl)); 68 } 69 rep(i,1,k-1) { 70 node a = q.top(); q.pop(); 71 int l = a.l, r = a.r, at = a.pos, id = a.id; 72 if( l < at ) { 73 ql = l, qr = at - 1; maxl = -inf; querymx(rot[id],1,n,0); 74 q.push(mkp(ql,qr,id,wh,maxl)); 75 } 76 if( at < r ) { 77 ql = at + 1, qr = r; maxl = -inf; querymx(rot[id],1,n,0); 78 q.push(mkp(ql,qr,id,wh,maxl)); 79 } 80 } 81 node a = q.top(); 82 printf("%lld ", a.v); 83 return 0; 84 } 85