Luo Gu [P2048] [stack] [super piano Chairman tree]

Subject to the effect:

Topic link: https://www.luogu.org/problemnew/show/P2048
a length n n sequences, seek m m length in [ l , r ] [l,r] sequences between, such that the elements of these sub-sequences and the maximum.


Ideas:

Obviously it is very difficult to engage in violence, taking first with a prefix and.
So we ask is that
i = 1 m m a x ( s u m [ k ] s u m [ x 1 ] ) ( x + l 1 k x + r 1 ) \sum^{m}_{i=1}max(sum[k]-sum[x-1])(x+l-1\leq k\leq x+r-1)
Consider split into m m times inquiry.
For each inquiry, we ask m a x ( s u m [ k ] s u m [ x 1 ] ) max(sum[k]-sum[x-1]) . Obviously for fixed x x s u m [ x 1 ] sum[x-1] is fixed. So long as we find m a x ( s u m [ k ] ) max(sum[k]) can be.
and k k is the required range. When the left point x x , the right end of the interval is fixed. Every time we requested within the maximum range, and then ask the second largest, followed by seeking third-largest.
This is obviously a static Interval k k big problem. Direct Chairman tree to get it.
Then we put all the points as the left point, and then find the corresponding point of the right and insert the pile. Each taking a maximum and maintenance click on it.
In fact, this step is tosequence the mergerof. Which will explain in more detail.
Such initialization O ( n log n ) O(n\log n) , each query O ( log n ) O(\log n) , total m m times asking, the total time complexity is O ( m log n ) O(m\log n) .
To open l o n g   l o n g long\ long .


Code:

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define mp make_pair
using namespace std;
typedef long long ll;
priority_queue<pair<ll,int> > q;

const int N=500010,M=500010*25;
int n,m,L,R,T,tot,root[N],num[N];
ll sum[N],b[N],ans;

struct Tree
{
    int ls,rs,cnt;
}tree[M];

int build(int l,int r)
{
    int p=++tot;
    if (l==r) return p;
    int mid=(l+r)/2;
    tree[p].ls=build(l,mid);
    tree[p].rs=build(mid+1,r);
    return p;
}

int insert(int now,int l,int r,int k)
{
    int p=++tot;
    tree[p]=tree[now];
    tree[p].cnt++;
    if (l==r) return p;
    int mid=(l+r)/2;
    if (k<=mid) tree[p].ls=insert(tree[p].ls,l,mid,k);
        else tree[p].rs=insert(tree[p].rs,mid+1,r,k);
    return p;
}

int ask(int x,int y,int l,int r,int k)
{
    if (l==r) return l;
    int mid=(l+r)/2,sum=tree[tree[y].ls].cnt-tree[tree[x].ls].cnt;
    if (sum>=k)
        return ask(tree[x].ls,tree[y].ls,l,mid,k);
    else return ask(tree[x].rs,tree[y].rs,mid+1,r,k-sum);
}
//以上主席树板子
int main()
{
    scanf("%d%d%d%d",&n,&m,&L,&R);
    for (int i=1;i<=n;i++)
    {
    	int x;
        scanf("%d",&x);
        sum[i]=sum[i-1]+x;
        b[i]=sum[i];
    }
    sort(b+1,b+1+n); 
    T=unique(b+1,b+1+n)-b-1;
    root[0]=build(1,T);
    for (int i=1;i<=n;i++)
        root[i]=insert(root[i-1],1,T,lower_bound(b+1,b+1+T,sum[i])-b);
    for (int i=1;i<=n;i++)
    {
    	int l=i+L-1,r=min(i+R-1,n);
    	if (l>n) break;
    	ll x=b[ask(root[l-1],root[r],1,T,(r-l+1))];
    	q.push(mp(x-sum[i-1],i));
    	num[i]=1;
	}
    while (m--)
    {
    	ans+=q.top().first;
        int i=q.top().second;
        q.pop();
        num[i]++;
        int l=i+L-1,r=min(i+R-1,n);
        if (l<=n&&num[i]<=r-l+1)
        {
      		ll x=b[ask(root[l-1],root[r],1,T,(r-l+1-num[i]+1))];
      		//静态区间第k大=静态区间第r-l+1-k+1小
    		q.push(mp(x-sum[i-1],i));
		}
    }
    printf("%lld\n",ans);
    return 0;
}

Guess you like

Origin blog.csdn.net/SSL_ZYC/article/details/94113889