BZOJ 4504: K个串

题目大意:

求一个序列的第k大的子串和。

题解:

对于一个右端点找最优的左端点,扔进堆里。

每次取堆顶,将这个右端点可以选择的左端点的区间分成两段,扔进堆里,重复k次。

现在需要对于一个固定的右端点,左端点在一个区间里,求最大值。

可持久化线段树上区间修改,不用标记永久化也可以过。

代码:

#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#define mp make_pair
#define pr pair<long long,int>
#define prr pair<pr,pr>
#define fr first
#define sc second
using namespace std;
int n,k,cnt,ls[10000005],rs[10000005],root[200005];
long long tag[10000005];
priority_queue<prr> q;
map<int,int> pre;
struct node{
	long long val;
	int id;
}tree[10000005];
void build(int &x,int l,int r){
	x=++cnt;
	tree[x]=(node){0,l};
	if (l==r) return;
	int mid=(l+r)>>1;
	build(ls[x],l,mid);
	build(rs[x],mid+1,r);
}
void add(int &now,int pre,long long key){
	now=++cnt;
	ls[now]=ls[pre],rs[now]=rs[pre],tree[now]=tree[pre],tag[now]=tag[pre]+key;
	tree[now].val+=key;
}
void push_down(int x){
	if (!tag[x]) return;
	add(ls[x],ls[x],tag[x]);
	add(rs[x],rs[x],tag[x]);
	tag[x]=0;
}
void insert(int &now,int pre,int l,int r,int x,int y,int key){
	if (l>y || r<x) return;
	if (l>=x && r<=y){
		add(now,pre,key);
		return;
	}
	push_down(pre);
	now=++cnt;
	ls[now]=ls[pre],rs[now]=rs[pre],tree[now]=tree[pre];
	int mid=(l+r)>>1;
	insert(ls[now],ls[pre],l,mid,x,y,key);
	insert(rs[now],rs[pre],mid+1,r,x,y,key);
	if (tree[rs[now]].val>tree[ls[now]].val) tree[now]=tree[rs[now]];
	else tree[now]=tree[ls[now]];
}
node query(int now,int l,int r,int x,int y){
	if (!now) return (node){-1ll<<60,0};
	if (l>y || r<x) return (node){-1ll<<60,0};
	if (l>=x && r<=y) return tree[now];
	push_down(now);
	int mid=(l+r)>>1;
	node max1=query(ls[now],l,mid,x,y);
	node max2=query(rs[now],mid+1,r,x,y);
	if (max1.val>max2.val) return max1;
	else return max2;
}
void insert(int x,int l,int r){
	if (l>r) return;
	node sum=query(x,1,n,l,r);
	q.push(mp(mp(sum.val,x),mp(l,r)));
}
int main(){
	scanf("%d%d",&n,&k);
	build(root[0],1,n);
	for (int i=1; i<=n; i++){
		int x;
		scanf("%d",&x);
		insert(root[i],root[i-1],1,n,pre[x]+1,i,x);
		pre[x]=i;
		insert(root[i],1,i);
	}
	long long sum;
	while (k--){
		sum=q.top().fr.fr;
		int id=q.top().fr.sc,l=q.top().sc.fr,r=q.top().sc.sc;
		q.pop();
		int mid=query(id,1,n,l,r).id;
		insert(id,l,mid-1);
		insert(id,mid+1,r);
	}
	printf("%lld\n",sum);
	return 0;
}

 

  

 

posted @ 2018-04-09 16:30  ~Silent  阅读(187)  评论(0编辑  收藏  举报
Live2D