【BZOJ4504】K个串 可持久化线段树+堆
【BZOJ4504】K个串
Description
兔子们在玩k个串的游戏。首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次)。兔子们想知道,在这个数字序列所有连续的子串中,按照以上方式统计其所有数字之和,第k大的和是多少。
Input
第一行,两个整数n和k,分别表示长度为n的数字序列和想要统计的第k大的和
接下里一行n个数a_i,表示这个数字序列
Output
一行一个整数,表示第k大的和
Sample Input
7 5
3 -2 1 2 2 1 3 -2
3 -2 1 2 2 1 3 -2
Sample Output
4
HINT
1 <= n <= 100000, 1 <= k <= 200000, 0 <= |a_i| <= 10^9数据保证存在第 k 大的和
题解:沿用超级钢琴的思路。用堆维护五元组(x,a,b,y,val)表示右端点为x,左端点在[a,b]中,最优的左端点是y,且y到x的和是val。然后每次从优先队列中取出val最大的,将其删去,在[a,y)和(y,b]中分别寻找新的y,然后将其扔回到队列中去。
问题是如何找y呢?考虑可持久化线段树。因为每个区间都是某个前缀的后缀,所以如果当前的右端点是x,x的前驱是pre[x],我们只需要在x的线段树中将(pre[x],x]的权值都加上val[x]即可。可以用标记永久化来加速主席树的区间修改。
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <queue> using namespace std; const int maxn=100010; typedef long long ll; int n,m,tot; ll v[maxn]; int rt[maxn],pre[maxn]; map<ll,int> last; struct node { int l,r,x,y; ll v; node() {} node(int a,int b,int c,ll d,int e) {x=a,l=b,r=c,v=d,y=e;} bool operator < (const node &a) const {return v<a.v;} }; struct sag { ll x; int y; sag() {x=-1ll<<60,y=0;} }s[maxn*100]; int ls[maxn*100],rs[maxn*100]; ll tag[maxn*100]; priority_queue<node> q; sag operator + (const sag &a,const sag &b) { return ((a.x==b.x)?(a.y>b.y):(a.x>b.x))?a:b; } void build(int l,int r,int &x) { x=++tot,s[x].x=0,s[x].y=l; if(l==r) return ; int mid=(l+r)>>1; build(l,mid,ls[x]),build(mid+1,r,rs[x]); } void insert(int x,int &y,int l,int r,int a,int b,ll c) { y=++tot,s[y]=s[x],ls[y]=ls[x],rs[y]=rs[x],tag[y]=tag[x]; if(a<=l&&r<=b) { s[y].x+=c,tag[y]+=c; return ; } int mid=(l+r)>>1; if(a<=mid) insert(ls[x],ls[y],l,mid,a,b,c); if(b>mid) insert(rs[x],rs[y],mid+1,r,a,b,c); s[y]=s[ls[y]]+s[rs[y]]; s[y].x+=tag[y]; } sag query(int l,int r,int x,int a,int b) { if(a<=l&&r<=b) return s[x]; int mid=(l+r)>>1; sag ret; ret.y=l; if(a<=mid) ret=ret+query(l,mid,ls[x],a,b); if(b>mid) ret=ret+query(mid+1,r,rs[x],a,b); ret.x+=tag[x]; return ret; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(); int i,a,b,x; ll y; sag t; node u; build(1,n,rt[0]); for(i=1;i<=n;i++) { v[i]=rd(),pre[i]=last[v[i]],last[v[i]]=i; insert(rt[i-1],rt[i],1,n,pre[i]+1,i,v[i]); t=query(1,n,rt[i],1,i); q.push(node(i,1,i,t.x,t.y)); } while(m--) { u=q.top(),q.pop(); x=u.x,a=u.l,b=u.r,y=u.y; if(!m) { printf("%lld\n",u.v); return 0; } if(a<y) { t=query(1,n,rt[x],a,y-1); q.push(node(x,a,y-1,t.x,t.y)); } if(b>y) { t=query(1,n,rt[x],y+1,b); q.push(node(x,y+1,b,t.x,t.y)); } } return 0; }//8 5 3 -2 1 2 2 1 3 -2
| 欢迎来原网站坐坐! >原文链接<