• [BZOJ2006][NOI2010]超级钢琴


    BZOJ
    Luogu

    sol

    有一个很暴力的想法,就是把所有合法的状态丢到一个堆里面,然后依次取出最大值。这样的话时间是(O(n^2logn)),空间是(O(n^2))
    我们考虑优化这个过程。对于右端点相同的所有合法区间,我们只在堆中保留最大的一个,在取出这一个以后再丢入次大的,取出次大的再丢入次次大的,以此类推。这样可以保证正确性,同时空间被优化到了(O(n))
    现在我们考虑怎么查这个次次次次(这里有若干个次)大值。
    首先把区间和转化成前缀和相减,因为我们固定了右端点,那么最大值就是对应了前缀和中减去的那个值最小。而第k大值刚好对应减去的那个数第k小,同时还要保证在一定区间范围内(L、R的限制)。所以离散前缀和以后主席树即可。
    注意前缀和减去的部分可以是0,所以0也要被离散进去。

    code

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define ll long long
    const int N = 500005;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    struct node{
    	int i,k,val;
    	bool operator < (const node &yyb) const
    		{return val<yyb.val;}
    };
    struct prisident_tree{int ls,rs,num;}t[N*30];
    int n,K,L,R,a[N],o[N],len,rt[N],tot;ll ans;
    priority_queue<node>Q;
    void modify(int &x,int l,int r,int p)
    {
    	t[++tot]=t[x];
    	t[x=tot].num++;
    	if (l==r) return;
    	int mid=l+r>>1;
    	if (p<=mid) modify(t[x].ls,l,mid,p);
    	else modify(t[x].rs,mid+1,r,p);
    }
    int query(int A,int B,int l,int r,int k)
    {
    	if (l==r) return l;
    	int sum=t[t[A].ls].num-t[t[B].ls].num,mid=l+r>>1;
    	if (k<=sum) return query(t[A].ls,t[B].ls,l,mid,k);
    	else return query(t[A].rs,t[B].rs,mid+1,r,k-sum);
    }
    int main()
    {
    	n=gi();K=gi();L=gi();R=gi();n++;
    	for (int i=2;i<=n;i++) a[i]=gi();
    	for (int i=1;i<=n;i++) o[++len]=a[i]=a[i]+a[i-1];
    	sort(o+1,o+len+1);len=unique(o+1,o+len+1)-o-1;
    	for (int i=1;i<=n;i++) a[i]=lower_bound(o+1,o+len+1,a[i])-o;
    	for (int i=1;i<=n;i++) rt[i]=rt[i-1],modify(rt[i],1,len,a[i]);
    	for (int i=L+1;i<=n;i++) Q.push((node){i,1,o[a[i]]-o[query(rt[i-L],rt[max(0,i-R-1)],1,len,1)]});
    	while (K--)
    	{
    		node tmp=Q.top();Q.pop();
    		ans+=tmp.val;
    		if (tmp.k==min(R-L+1,tmp.i-L)) continue;
    		tmp.k++;
    		tmp.val=o[a[tmp.i]]-o[query(rt[tmp.i-L],rt[max(0,tmp.i-R-1)],1,len,tmp.k)];
    		Q.push(tmp);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C语言与内存模型初探
    【编辑中】软件工程知识萃取
    【深入理解计算机系统01】不同层级程序指令间的转换
    【统计学中的普适智慧】假设检验
    windows 内部预览版与迅雷极速版不配合
    网络安全理论初涉
    Unix philosophy
    BOP 2016 复赛题目
    10.8做题——USACO1.2命名那个数字(Name That Number)
    10.6上课——problem1切割木板(USACO 2006 November Gold)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8336351.html
Copyright © 2020-2023  润新知