bzoj 4504: K个串【大根堆+主席树】

像超级钢琴一样把五元组放进大根堆,每次取一个出来拆开,(d,l,r,p,v)表示右端点为d,左端点区间为(l,r),最大区间和值为v左端点在p上
关于怎么快速求区间和,用可持久化线段树维护(主席树?)每个点到他root的区间和,这样每次右端点右移就是上一个的线段树在(la[a[i]]+1,i)加上a[i],la是这个值a[i]上一次出现的位置
然后就可以在线处理询问了
有一点因为这个线段树建的是1~n,所以右端点不是n的时候取max会取到右端点向右还是初始值0的位置(有可能前面是负数),这样的解决方法就是先全填成-inf,然后每次右移的时候先把右端点加上inf再处理区间加

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
const int N=300005;
int n,m,has,rt[N],tot,la[N];
long long a[N],g[N],rl[N],ans;
map<long long ,int>mp;
struct zxs
{
	int ls,rs,p;
	long long mx,lz;
}t[7000005];
struct qwe
{
	int d,l,r,p;
	long long v;
	qwe(int D=0,int L=0,int R=0,int P=0,long long V=0)
	{
		d=D,l=L,r=R,p=P,v=V;
	}
	bool operator < (const qwe &a) const
	{
		return v<a.v;
	}
};
priority_queue<qwe>q;
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
void build(int &ro,int l,int r)
{
	ro=++tot;
	t[ro].p=l,t[ro].mx=-1e15;
	if(l==r)
		return;
	int mid=(l+r)>>1;
	build(t[ro].ls,l,mid);
	build(t[ro].rs,mid+1,r);
}
void ud(int ro)
{
	if(t[t[ro].ls].mx>t[t[ro].rs].mx)
		t[ro].mx=t[t[ro].ls].mx,t[ro].p=t[t[ro].ls].p;
	else
		t[ro].mx=t[t[ro].rs].mx,t[ro].p=t[t[ro].rs].p;
}
void update(int &ro,int la,int l,int r,int ll,int rr,long long v,long long lz)
{
	ro=++tot;
	t[ro]=t[la];
	t[ro].lz+=lz;
	t[ro].mx+=lz;
	if(l==ll&&r==rr)
	{
		t[ro].lz+=v;
		t[ro].mx+=v;
		return;
	}
	int mid=(l+r)>>1;
	if(t[ro].lz)
	{
		if(rr<=mid)
		{
			t[ro].rs=++tot;
			t[t[ro].rs]=t[t[la].rs];
			t[t[ro].rs].mx+=t[ro].lz;
			t[t[ro].rs].lz+=t[ro].lz;
			update(t[ro].ls,t[la].ls,l,mid,ll,rr,v,t[ro].lz);
		}
		else if(ll>mid)
		{
			t[ro].ls=++tot;
			t[t[ro].ls]=t[t[la].ls];
			t[t[ro].ls].mx+=t[ro].lz;
			t[t[ro].ls].lz+=t[ro].lz;
			update(t[ro].rs,t[la].rs,mid+1,r,ll,rr,v,t[ro].lz);
		}
		else
		{
			update(t[ro].ls,t[la].ls,l,mid,ll,mid,v,t[ro].lz);
			update(t[ro].rs,t[la].rs,mid+1,r,mid+1,rr,v,t[ro].lz);
		}
		t[ro].lz=0;
	}
	else
	{
		if(rr<=mid)
			update(t[ro].ls,t[la].ls,l,mid,ll,rr,v,0);
		else if(ll>mid)
			update(t[ro].rs,t[la].rs,mid+1,r,ll,rr,v,0);
		else
		{
			update(t[ro].ls,t[la].ls,l,mid,ll,mid,v,0);
			update(t[ro].rs,t[la].rs,mid+1,r,mid+1,rr,v,0);
		}
	}
	ud(ro);
}
pair<long long,int> ques(int ro,int l,int r,int ll,int rr)
{//cerr<<l<<" "<<r<<"   "<<ll<<" "<<rr<<endl;
	if(l==ll&&r==rr)
		return make_pair(t[ro].mx,t[ro].p);
	if(t[ro].lz)
	{
		t[tot+1]=t[t[ro].ls];
		t[tot+1].mx+=t[ro].lz;
		t[tot+1].lz+=t[ro].lz;
		t[ro].ls=tot+1;
		t[tot+2]=t[t[ro].rs];
		t[tot+2].mx+=t[ro].lz;
		t[tot+2].lz+=t[ro].lz;
		t[ro].rs=tot+2;
		tot+=2;
		t[ro].lz=0;
	}
	int mid=(l+r)>>1;
	if(rr<=mid)
		return ques(t[ro].ls,l,mid,ll,rr);
	else if(ll>mid)
		return ques(t[ro].rs,mid+1,r,ll,rr);
	else
	{
		pair<long long,int>a=ques(t[ro].ls,l,mid,ll,mid),b=ques(t[ro].rs,mid+1,r,mid+1,rr);
		return (a.first>b.first)?a:b;
	}
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)
		a[i]=g[i]=read();
	sort(g+1,g+1+n);
	for(int i=1;i<=n;i++)
		if(i==1||g[i]!=g[i-1])
			mp[g[i]]=++has,rl[has]=g[i];
	build(rt[0],1,n);
	for(int i=1;i<=n;i++)
	{
		update(rt[i],rt[i-1],1,n,i,i,1e15,0);
		update(rt[i],rt[i],1,n,la[mp[a[i]]]+1,i,a[i],0);
		la[mp[a[i]]]=i;//cerr<<"OK"<<endl;
	}
	for(int i=1;i<=n;i++)
		q.push(qwe(i,1,i,t[rt[i]].p,t[rt[i]].mx));
	while(m--)
	{
		qwe u=q.top();
		q.pop();
		ans=u.v;//cerr<<ans<<endl;
		if(u.l<=u.p-1)
		{
			pair<long long,int>nw=ques(rt[u.d],1,n,u.l,u.p-1);
			q.push(qwe(u.d,u.l,u.p-1,nw.second,nw.first));
		}
		if(u.p+1<=u.r)
		{
			pair<long long,int>nw=ques(rt[u.d],1,n,u.p+1,u.r);
			q.push(qwe(u.d,u.p+1,u.r,nw.second,nw.first));
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2019-04-05 18:46  lokiii  阅读(178)  评论(0编辑  收藏  举报