题解 串
- 求前k大的另一种思路:降维
当题目要求区间/点对第k大时,考虑对每个左端点/点维护最大的右端点/另一个点
用一个堆维护每个左端点编号及其对应的权值
每次取出并删除取到最大值的决策点,并加入次大的,重复 \(k-1\) 次即可
于是考虑对每个左端点维护所有右端点答案的最大值
发现暴力预处理左端点为1的情况,要转移到2的情况就是单点将1处改为-inf,将区间 \([2, nxt[a[1]]]\) 整体减去 \(a_1\) 即可
可以主席树维护
每次取出一个点时就将这个点单点改为-inf
复杂度 \(O((n+k)logn)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 200010
#define ll long long
#define fir first
#define sec second
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, k;
int a[N];
namespace force{
ll uni[N], usiz;
map<ll, bool> mp;
void solve() {
for (int l=1; l<=n; ++l) {
ll sum=0; mp.clear();
for (int r=l; r<=n; ++r) {
if (mp.find(a[r])==mp.end()) {
mp[a[r]]=1;
sum+=a[r];
}
uni[++usiz]=sum;
}
}
sort(uni+1, uni+usiz+1);
cout<<uni[usiz-k+1]<<endl;
exit(0);
}
}
namespace task1{
map<int, bool> exi;
map<pair<int, int>, bool> mp;
set<int> s[100010];
int uni[N], usiz, c[N];
struct st{ll sum; int l, r;}t;
inline bool operator < (st a, st b) {return a.sum<b.sum;}
priority_queue<st> q;
void solve() {
ll sum=0;
for (int i=1; i<=n; ++i) if (exi.find(a[i])==exi.end()) {
exi[a[i]]=1;
sum+=a[i];
}
q.push({sum, 1, n});
for (int i=1; i<=n; ++i) uni[++usiz]=a[i];
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
for (int i=1; i<=n; ++i) {
c[i]=lower_bound(uni+1, uni+usiz+1, a[i])-uni;
s[c[i]].insert(i);
}
for (int i=1; i<k; ++i) {
t=q.top(); q.pop();
if (t.l<t.r) {
if (mp.find({t.l+1, t.r})==mp.end()) {
ll tsum=t.sum;
if (s[c[t.l]].upper_bound(t.l)==s[c[t.l]].end() || *s[c[t.l]].upper_bound(t.l)>t.r) tsum-=a[t.l];
mp[{t.l+1, t.r}]=1, q.push({tsum, t.l+1, t.r});
}
if (mp.find({t.l, t.r-1})==mp.end()) {
ll tsum=t.sum;
if (s[c[t.r]].lower_bound(t.l)==s[c[t.r]].end() || *s[c[t.r]].lower_bound(t.l)>t.r) tsum-=a[t.r];
mp[{t.l, t.r-1}]=1, q.push({tsum, t.l, t.r-1});
}
}
}
cout<<q.top().sum<<endl;
}
}
namespace task{
bool vis[N];
ll b[N], mx[N*130], tag[N*130];
priority_queue<pair<ll, int>> q;
int uni[N], c[N], nxt[N], lst[N], pos[N], usiz;
int lson[N*130], rson[N*130], mps[N*130], rot[N<<2], now, tot;
#define ls(p) lson[p]
#define rs(p) rson[p]
inline void pushup(int p) {
if (!ls(p)) mx[p]=mx[rs(p)], mps[p]=mps[rs(p)];
else if (!rs(p)) mx[p]=mx[ls(p)], mps[p]=mps[ls(p)];
else {
mx[p]=max(mx[ls(p)], mx[rs(p)]);
if (mx[ls(p)]==mx[p]) mps[p]=mps[ls(p)];
else mps[p]=mps[rs(p)];
}
mx[p]+=tag[p];
}
void upd(int& p1, int p2, int tl, int tr, int ql, int qr, ll val) {
// cout<<"upd: "<<p1<<' '<<p2<<' '<<tl<<' '<<tr<<' '<<ql<<' '<<qr<<' '<<val<<endl;
p1=++tot; ls(p1)=ls(p2); rs(p1)=rs(p2); tag[p1]=tag[p2];
if (ql<=tl&&qr>=tr) {
if (val==-INF) {tag[p1]=mx[p1]=-INF; assert(tl==tr);}
else {tag[p1]=tag[p2]+val; mx[p1]=mx[p2]+val; mps[p1]=(tl==tr)?tl:mps[p2];}
return ;
}
int mid=(tl+tr)>>1;
if (ql<=mid) upd(ls(p1), ls(p2), tl, mid, ql, qr, val);
if (qr>mid) upd(rs(p1), rs(p2), mid+1, tr, ql, qr, val);
pushup(p1);
}
void solve() {
// cout<<double(sizeof(tag)*2+sizeof(lson)*3)/1000/1000<<endl;
for (int i=1; i<=n; ++i) uni[++usiz]=a[i];
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
for (int i=1; i<=n; ++i) c[i]=lower_bound(uni+1, uni+usiz+1, a[i])-uni;
for (int i=n; i; --i) {
nxt[i]=lst[c[i]]?lst[c[i]]:n+1;
lst[c[i]]=i;
}
for (int i=1; i<=n; ++i) b[i]=b[i-1]+(vis[c[i]]?0:a[i]), vis[c[i]]=1;
// cout<<"b: "; for (int i=1; i<=n; ++i) cout<<b[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) ++now, upd(rot[now], rot[now-1], 1, n, i, i, b[i]);
pos[1]=now; q.push({mx[rot[pos[1]]], 1});
// cout<<"ins: "<<1<<' '<<mx[rot[pos[1]]]<<endl;
for (int i=2; i<=n; ++i) {
++now, upd(rot[now], rot[now-1], 1, n, i-1, i-1, -INF);
++now, upd(rot[now], rot[now-1], 1, n, i, nxt[i-1]-1, -a[i-1]);
pos[i]=now; q.push({mx[rot[now]], i});
// cout<<"ins: "<<i<<' '<<mx[rot[now]]<<' '<<mps[rot[now]]<<endl;
}
for (int i=1; i<k; ++i) {
// cout<<"i: "<<i<<endl;
pair<ll, int> u=q.top(); q.pop();
// cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
assert(u.fir>-INF);
// cout<<1<<endl;
// cout<<mps[pos[u.sec]]<<endl;
upd(rot[++now], rot[pos[u.sec]], 1, n, mps[rot[pos[u.sec]]], mps[rot[pos[u.sec]]], -INF);
// cout<<2<<endl;
pos[u.sec]=now; q.push({mx[rot[now]], u.sec});
// cout<<"push: "<<mx[now]<<endl;
// cout<<3<<endl;
}
printf("%lld\n", q.top().fir);
}
}
signed main()
{
n=read(); k=read();
for (int i=1; i<=n; ++i) a[i]=read();
task::solve();
return 0;
}