您的位置:首页 > 其它

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

2016-05-05 21:13 183 查看
这道题因为有一个数在序列中出现多次只算一次的限制。我们可以这样搞。假设在当前题意下求给定右端点的区间最值。那么我们可以预处理出每个数前一次出现的位置pre[i] 。接下来从左到右加入每一个值,就是在 pre[i] + 1 —— i 这个区间内加上 v[i] 的值,这样就可以得到以当前 i 点为右端点的各个区间的值(很明显维护一下最值就好了)。接下来很明显有n个版本的线段树(如果你说一开始那个空的线段树也算一个版本的话,就有n+1个),那就要用主席树动态开点。而取第K大值的操作有点像超级钢琴,不过在这里要维护5元组吧! 分别是 区间左端点, 区间右端点, 区间最值点, 区间最值, 线段树版本。 没了!就这样!

#include<cstdio>
#include<queue>
#include<iostream>
#include<map>
#define rep(i,j,k) for(register int i = j; i <= k; i++)
#define maxn 100005
#define ll long long
#define inf 1ll * 10000000 * 10000000
using namespace std;

inline int read() {
int s = 0, t = 1; char c = getchar();
while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); }
while( isdigit(c) ) s = s * 10 + c - 48, c = getchar();
return s * t;
}

int ql, qr, d, tot = 0, rot[maxn], c[maxn*100][2], pos[maxn*100]; ll sum[maxn*100], v[maxn*100];
#define lc c[k][0]
#define rc c[k][1]
#define mid ((l+r)>>1)
inline void build(int l,int r,int &k) {
k = ++tot; pos[k] = l;
if( l == r ) return;
build(l,mid,lc); build(mid+1,r,rc);
}
inline void update(int &k,int pre,int l,int r) {
k = ++tot;
sum[k] = sum[pre], v[k] = v[pre];
lc = c[pre][0], rc = c[pre][1];
if( ql <= l && r <= qr ) { sum[k] += d; v[k] += d; pos[k] = pos[pre]; return; }
if( ql <= mid ) update(lc,c[pre][0],l,mid); else lc = c[pre][0];
if( qr > mid ) update(rc,c[pre][1],mid+1,r); else rc = c[pre][1];
if( sum[lc] > sum[rc] ) sum[k] = sum[lc] + v[k], pos[k] = pos[lc];
else sum[k] = sum[rc] + v[k], pos[k] = pos[rc];
}

int wh; ll maxl;
inline void querymx(int k,int l,int r, ll pd) {
if( ql <= l && r <= qr ) {
if( sum[k] + pd > maxl ) maxl = sum[k] + pd, wh = pos[k];
return;
}
if( ql <= mid ) querymx(lc,l,mid,pd+v[k]);
if( qr > mid ) querymx(rc,mid+1,r,pd+v[k]);
}

inline void out(int k,int l,int r,ll pd) {
if( l == r ) { cout<<pd+sum[k]<<" "; return; }
out(lc,l,mid,pd+v[k]); out(rc,mid+1,r,pd+v[k]);
}

map<int,int> last; int pre[maxn], val[maxn];
struct node{ int l, r, id, pos; ll v; bool operator < (const node&rhs) const { return v < rhs.v; }; };
priority_queue<node> q;
#define mkp(i,j,k,l,d) (node){i,j,k,l,d}
int main() {
int n = read(), k = read();
rep(i,1,n) val[i] = read(), pre[i] = last[val[i]], last[val[i]] = i;;
build(1,n,rot[0]);
rep(i,1,n) {
ql = pre[i] + 1, qr = i, d = val[i];
update(rot[i],rot[i-1],1,n);
ql = 1, qr = i; maxl = -inf;
querymx(rot[i],1,n,0);
//out(rot[i],1,n,0); cout<<endl;
q.push(mkp(1,i,i,wh,maxl));
}
rep(i,1,k-1) {
node a = q.top(); q.pop();
int l = a.l, r = a.r, at = a.pos, id = a.id;
if( l < at ) {
ql = l, qr = at - 1; maxl = -inf; querymx(rot[id],1,n,0);
q.push(mkp(ql,qr,id,wh,maxl));
}
if( at < r ) {
ql = at + 1, qr = r; maxl = -inf; querymx(rot[id],1,n,0);
q.push(mkp(ql,qr,id,wh,maxl));
}
}
node a = q.top();
printf("%lld\n", a.v);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: