【bzoj4504】k个串

Portal -->bzoj4504

Description

  给你一个数列,定义一个连续子串的和为这个子串中所有的数字之和(相同的数字只算一次),求这个数列的所有连续子串的和中第(k)大的和是多少

  范围:(1<=n<=10^5,1<=k<=2*10^5,0<=|a_i|<=10^9),保证有解

Solution

  额因为是权限题所以简单写一下题面。。

  感觉自己好像还是不太。。会用这种统计的思路呀qwq就是固定一端看另一端的qwq所以还是没有在场上想出来qwq以及求第(k)大不是只有二分之类的方法的好吧Q^Q怎么把最简单粗暴的那种给忘了qwq

  

  (注意:以下涉及到的所有的子串和指的都是相同数字只算一次的)

​  首先看看如果说不是第(k)大而是最大要怎么做

  可以有一个比较简单粗暴的想法,我们记(f[i])为以位置(i)为连续子串左端点的子串和的大小,那么答案显然就是(max(f[i]))

  那如果是要求第(k)大怎么办呢?

​  那也有一个很简单粗暴的想法,就是不停删掉当前最大的那个(f[i]),然后用其次小值来替代,这样操作(k-1)次之后,(max(f[i]))就是我们要的答案了

  这部分的实现可以用一个堆来维护(或者直接调用优先队列)

  

​  现在的问题是怎么维护(f[i])

  显然离散化之后(f[1])是可以直接计算的,因为我们可以很轻易地算出以(1)为左端点的每个连续子串的和,为了方便接下来的表述,记为(b_1[i])为连续子串([1,i])的子串和

  然后接着看看如何得到(f[2])

  我们记(nxt[i])表示(a[i])这个数在(i)这个位置的下一个出现位置的下标,那么我们会发现当子串从(2)开始的时候,我们的(b_2[i])中只有([2,nxt[a[1]]))这个区间中的值会受到影响,这个范围内的(b_2[i])都要(-a[1]),并且(b_2[1])会变得不合法,而不在这个范围以内的(b_2[i])的值则与(b_1[i])相同

​  同理我们可以由(b_i)推得(b_{i+1})

  那所以我们可以考虑用主席树来维护(f[i])了,只要把(b[i])的值丢进去然后求个最大值就好了,具体一点就是:从以(i)为左端点到以(i+1)为左端点,我们只需要对区间([i,nxt[a[i-1]))减去(a[i-1]),将(i-1)这个位置减去(inf)(也就是保证这个位置不会成为最大值)就好了,同理如果说是删掉最大值的话,我们对最大值那个位置减去(inf)即可

  这样一来我们就可以快速查得(f[i])以及删掉最大值之后的答案了,加个优先队列或者堆这题就很愉快滴做完啦ovo

  因为是可持久化的主席树,区间修改我们标记永久化一下(然而貌似下传也可以就是空间会开大许多),注意递归传参的时候有一点点小不同

  

​  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int N=100010,SEG=N*100;
const int ll inf=1e15;
struct Data{
	int rt,loc;
	ll val;
	Data(){}
	Data(int _rt,int _loc,ll _val){rt=_rt; loc=_loc; val=_val;}
	friend bool operator < (Data x,Data y)
	{return x.val<y.val;}
};
int a[N],V[N],Lis[N],loc[N],nxt[N];
ll b[N];
int vis[N];
int n,m;
priority_queue<Data> q;
namespace Seg{/*{{{*/
	int ch[SEG][2],rt[N*3],loc[SEG];
	ll mx[SEG],tag[SEG];
	int tot,n;
	int newnode(int pre){
		ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1]; tag[tot]=tag[pre]; mx[tot]=mx[pre];
		loc[tot]=loc[pre];
		return tot;
	}
	void pushup(int x){
		if (mx[ch[x][0]]+tag[ch[x][0]]>mx[ch[x][1]]+tag[ch[x][1]])
			mx[x]=mx[ch[x][0]]+tag[ch[x][0]],loc[x]=loc[ch[x][0]];
		else
			mx[x]=mx[ch[x][1]]+tag[ch[x][1]],loc[x]=loc[ch[x][1]];
	}
	void _build(int x,int l,int r){
		tag[x]=0; mx[x]=0;
		if (l==r){mx[x]=b[l];loc[x]=l; return;}
		int mid=l+r>>1;
		ch[x][0]=++tot; _build(ch[x][0],l,mid);
		ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
		pushup(x);
	}
	void build(int _n){n=_n; tot=rt[1]=1; _build(1,1,n);}
	void _update(int pre,int &x,int l,int r,int lx,int rx,ll delta){
		x=newnode(pre);
		if (l<=lx&&rx<=r){tag[x]+=delta;return;}
		int mid=lx+rx>>1;
		if (r<=mid) _update(ch[pre][0],ch[x][0],l,r,lx,mid,delta);
		else if (l>mid) _update(ch[pre][1],ch[x][1],l,r,mid+1,rx,delta);
		else {
			_update(ch[pre][0],ch[x][0],l,mid,lx,mid,delta);
			_update(ch[pre][1],ch[x][1],mid+1,r,mid+1,rx,delta);
		}
		pushup(x);
	}
	void update(int pre,int x,int l,int r,ll delta){_update(rt[pre],rt[x],l,r,1,n,delta);}
	Data query(int x){return Data(x,loc[rt[x]],mx[rt[x]]+tag[rt[x]]);}
}/*}}}*/
void prework(int n){
	sort(Lis+1,Lis+1+Lis[0]);
	Lis[0]=unique(Lis+1,Lis+1+Lis[0])-Lis-1;
	for (int i=1;i<=n;++i){
		int x=lower_bound(Lis+1,Lis+1+Lis[0],a[i])-Lis;
		V[x]=a[i]; a[i]=x;
	}
	
	for (int i=1;i<=n;++i) nxt[i]=n+1;
	for (int i=1;i<=n;++i){
		if (loc[a[i]])
			nxt[loc[a[i]]]=i;
		loc[a[i]]=i;
	}
	memset(vis,0,sizeof(vis));
	for (int i=1;i<=n;++i){
		if (!vis[a[i]]) b[i]=b[i-1]+V[a[i]];
		else b[i]=b[i-1];
		vis[a[i]]=1;
	}
}

void solve(){
	Seg::build(n);
	for (int i=2;i<=n;++i){
		if (i<=nxt[i-1]-1) 
			Seg::update(i-1,i,i,nxt[i-1]-1,-V[a[i-1]]);
		else
			Seg::update(i-1,i,1,n,0);
		Seg::update(i,i,i-1,i-1,-inf);
	}
	for (int i=1;i<=n;++i){
		q.push(Seg::query(i));
		//printf("%d %d
",Seg::loc[Seg::rt[i]],Seg::mx[Seg::rt[i]]);
	}
	Data now;
	for (int i=1;i<m;++i){
		now=q.top(); q.pop();
		Seg::update(now.rt,n+i,now.loc,now.loc,-inf);
		q.push(Seg::query(n+i));
	}
	now=q.top();
	printf("%lld
",now.val);
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i)
		scanf("%d",a+i),Lis[++Lis[0]]=a[i];
	prework(n);
	solve();
}
原文地址:https://www.cnblogs.com/yoyoball/p/9318301.html