• K大数查询


    前言

    摸到一点整体二分的门路了,写一写吧。

    WARNING:笔者可能自己都没懂而是在瞎BB,谨慎食用!

    题目

    洛谷

    讲解

    我们从这道例题入手整体二分。

    在背了多次代码后,我终于悟到了整体二分的精髓。

    有多个询问,每个询问单独来做都可以二分!

    而整体二分又与 ( t dp) 有点类似,在本区间处理询问之后,将询问状态更新,变为子区间的询问,然后递归地下去处理。

    而我们二分的自然就是答案了。

    比如这道题,首先区间查询区间修改可以用树状数组实现,不再赘述。

    对于一个区间,我们二分一个答案,我们将所有修改大于它的数都加入树状数组。

    对于询问,我们直接计算区间和再与排名比较即可,由于是第K,所以询问排名小放在右区间,否则放在左区间。

    记得清空树状数组。

    时间复杂度 (O(nlog^2n))

    多看看代码就懂了。

    代码

    int ans[MAXN];
    struct node
    {
    	int opt,l,r,ID;
    	LL c;
    }s[MAXN],z[MAXN],y[MAXN];
    LL t1[MAXN],t2[MAXN];
    int lowbit(int x){return (x & -x);}
    void Add(int x,LL val){for(int i = x;i <= n;i += lowbit(i)) t1[i] += val,t2[i] += (x-1) * val;}
    void Add(int l,int r,LL val){Add(l,val);Add(r+1,-val);}
    LL Sum(LL x){LL ret = 0;for(int i = x;i >= 1;i -= lowbit(i)) ret += t1[i] * x - t2[i];return ret;}
    
    void solve(int ql,int qr,int l,int r)
    {
    	if(ql > qr) return;
    	if(l == r)
    	{
    		for(int i = ql;i <= qr;++ i) if(s[i].opt == 2) ans[s[i].ID] = l;
    		return;
    	}
    	int mid = (l+r) >> 1,zt = 0,yt = 0;
    	for(int i = ql;i <= qr;++ i)
    	{
    		if(s[i].opt == 1)
    		{
    			if(s[i].c > mid) Add(s[i].l,s[i].r,1),y[++yt] = s[i];
    			else z[++zt] = s[i];
    		}
    		else
    		{
    			LL dz = Sum(s[i].r) - Sum(s[i].l-1);
    			if(s[i].c <= dz) y[++yt] = s[i];
    			else s[i].c -= dz,z[++zt] = s[i];
    		}
    	}
    	int now = ql;
    	for(int i = ql;i <= qr;++ i)
    		if(s[i].opt == 1 && s[i].c > mid) Add(s[i].l,s[i].r,-1);
    	for(int i = 1;i <= zt;++ i) s[now++] = z[i];
    	for(int i = 1;i <= yt;++ i) s[now++] = y[i];
    	solve(ql,ql+zt-1,l,mid); solve(ql+zt,qr,mid+1,r);
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); m = Read();
    	for(int i = 1;i <= m;++ i) 
    	{
    		s[i].opt = Read();
    		s[i].l = Read(),s[i].r = Read(),s[i].c = Read();
    		s[i].ID = i;
    	}
    	solve(1,m,1,n);//数据似乎有点水,并没有负数的情况,所以。。。
    	for(int i = 1;i <= m;++ i) if(ans[i]) Put(ans[i],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    安装nginx
    查看Linux内核
    Python学习总结11:获取当前运行类名和函数名
    Python学习总结10:获取shell输出结果
    Python学习总结9:目录操作方法汇总
    Python学习总结8:文件模式及操作方法汇总
    Python学习总结7:随机字符串和随机数
    Python学习总结6:字符串格式化操作及方法总结
    Python学习总结5:数据类型及转换
    Python学习总结4:字符串常量与操作汇总
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14407738.html
Copyright © 2020-2023  润新知