题解 串

传送门

  • 求前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;
}
posted @ 2021-12-18 20:29  Administrator-09  阅读(3)  评论(0编辑  收藏  举报