4504: K个串 主席树+优先队列

这道题因为有一个数在序列中出现多次只算一次的限制。我们可以这样搞。假设在当前题意下求给定右端点的区间最值。那么我们可以预处理出每个数前一次出现的位置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\n", a.v);
83     return 0;
84 }
85 

 

posted on 2016-05-05 21:13  83131  阅读(125)  评论(0编辑  收藏  举报

导航