hihocoder#1046 K個串 可持久化線段樹 + 堆
阿新 • • 發佈:2018-12-04
首先考慮二分,然後發現不可行....
注意到\(k\)十分小,嘗試從這裡突破
首先用掃描線來處理出以每個節點為右端點的區間的權值和,用可持久化線段樹存下來
在所有的右端點相同的區間中,挑一個權值最大的,放入堆中
每次從堆中取出最大元素,然後從被刪除的右端點區間中選一個次大的區間
重複\(k\)次即可
複雜度\(O(n \log n + k \log n)\)
一\(A\)開心
#include <map> #include <queue> #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define ll long long #define ri register int #define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define drep(io, ed, st) for(ri io = ed; io >= st; io --) #define gc getchar inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc(); return p * w; } const int sid = 1e5 + 5; const int eid = 2e7 + 5; int n, k, id, a[sid], rt[sid]; map <int, int> lst; ll tag[eid]; int ls[eid], rs[eid]; struct ym { ll max; int maxp; friend bool operator < (ym a, ym b) { return a.max < b.max; } } t[eid]; priority_queue < pair <ym, int> > q; inline int newnode(int pre) { ++ id; if(pre) t[id] = t[pre]; tag[id] = tag[pre]; ls[id] = ls[pre]; rs[id] = rs[pre]; return id; } inline void mdf(int &o, int p, int l, int r, int ml, int mr, ll v) { o = newnode(p); if(ml <= l && mr >= r) { tag[o] += v; t[o].max += v; if(l == r) t[o].maxp = l; return; } int mid = (l + r) >> 1; if(ml <= mid) mdf(ls[o], ls[p], l, mid, ml, mr, v); if(mr > mid) mdf(rs[o], rs[p], mid + 1, r, ml, mr, v); t[o] = max(t[ls[o]], t[rs[o]]); t[o].max += tag[o]; } void wish_upon_to_the_star() { t[0].max = -1e16; rep(i, 1, n) { mdf(rt[i], rt[i - 1], 1, n, i, i, 0); mdf(rt[i], rt[i], 1, n, lst[a[i]] + 1, i, a[i]); lst[a[i]] = i; q.push(make_pair(t[rt[i]], i)); } ll ans = 0; while(k --) { ym tmp = q.top().first; int id = tmp.maxp, pos = q.top().second; q.pop(); ans = tmp.max; mdf(rt[pos], rt[pos], 1, n, id, id, -1e16); q.push(make_pair(t[rt[pos]], pos)); } printf("%lld\n", ans); } int main() { n = read(); k = read(); rep(i, 1, n) a[i] = read(); wish_upon_to_the_star(); return 0; }