bzoj 4504: K个串

求全局第k大,k比较小,不难想到要找到当前最大的数之后去拓展几个小一点的数。
用主席树维护右端点是每个数时左端点的答案,发现加入一个数后更改的是[pre[i],i]连续的一段
开始我自己想,把根节点加入堆中,然后每次加入它的两个儿子节点,如果l==r就是答案,但是这样很难处理答案为负数的情况
实际上,堆中维护的是五元组(root,l,r,id,mx)表示现在的右端点是root,当前代表的区间是l,r,这其中取到的最大值是mx,位置是id。
然后,每次出堆后加入(root,l,id-1,?,?), (root,id+1,r,?,?)
    
    
    
    
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define TR 7000010
using namespace std;
map<int,int> mp;
struct QQ { int rt,l,r,id; ll mx;};
struct cmp
{
bool operator () (QQ a,QQ b) { return a.mx<b.mx;}
};
priority_queue<QQ,vector<QQ>,cmp> q;
struct Tr { ll mx; int id;} tr[TR];
int ch[TR][2];
ll ad[TR],mx[TR];
int root[100010];
int cnt=0;
 
Tr update(Tr a,Tr b)
{
Tr ans;
if (b.mx>a.mx) ans=b;
else ans=a;
return ans;
}
 
void insert(int &i,int pre,int l,int r,int ql,int qr,int d)
{
i=++cnt; ch[i][0]=ch[pre][0]; ch[i][1]=ch[pre][1]; ad[i]=ad[pre];
if (ql<=l&&r<=qr) { ad[i]+=d; tr[i].mx=tr[pre].mx+d; tr[i].id=tr[pre].id; return; }
int mid=(l+r)>>1;
if (ql<=mid) insert(ch[i][0],ch[pre][0],l,mid,ql,qr,d);
if (mid+1<=qr) insert(ch[i][1],ch[pre][1],mid+1,r,ql,qr,d);
tr[i]=update(tr[ch[i][0]],tr[ch[i][1]]);
tr[i].mx+=ad[i];
}
 
void build(int &i,int l,int r)
{
i=++cnt; tr[i].id=l;
if (l==r) return;
int mid=(l+r)>>1;
build(ch[i][0],l,mid); build(ch[i][1],mid+1,r);
}
 
Tr query(int i,int l,int r,int ql,int qr)
{
if (ql<=l&&r<=qr) return tr[i];
int mid=(l+r)>>1; Tr ans;
if (qr<=mid) ans=query(ch[i][0],l,mid,ql,qr);
else if (mid+1<=ql) ans=query(ch[i][1],mid+1,r,ql,qr);
else ans=update(query(ch[i][0],l,mid,ql,qr),query(ch[i][1],mid+1,r,ql,qr));
ans.mx+=ad[i];
return ans;
}
 
int main()
{
int n,k;
scanf("%d%d",&n,&k);
build(root[0],1,n);
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
int pre=mp[x]; mp[x]=i;
insert(root[i],root[i-1],1,n,pre+1,i,x);
Tr ans=query(root[i],1,n,1,i);
q.push((QQ){root[i],1,i,ans.id,ans.mx});
}
ll ans=0;
for (int i=1;i<=k;i++)
{
QQ x=q.top(); q.pop();
ans=x.mx;
if (x.l<x.id)
{
Tr qu=query(x.rt,1,n,x.l,x.id-1);
q.push((QQ){x.rt,x.l,x.id-1,qu.id,qu.mx});
}
if (x.id<x.r)
{
Tr qu=query(x.rt,1,n,x.id+1,x.r);
q.push((QQ){x.rt,x.id+1,x.r,qu.id,qu.mx});
}
}
printf("%lld\n",ans);
return 0;
}

你可能感兴趣的:(bzoj 4504: K个串)