• jzoj 4438.【HNOI2016模拟4.10】 K小数查询


    Description
    在这里插入图片描述

    Input
    在这里插入图片描述

    Output
    在这里插入图片描述

    Sample Input
    4
    2 1 1 3
    3
    2 2 4 2
    1 1 3 3
    2 1 4 3

    Sample Output
    1
    4

    Data Constraint
    在这里插入图片描述

    Hint
    在这里插入图片描述
    这道题就是分块了。
    我们用a[]表示输入的东西,用b[]表示输入的东西按照每个块从小到大排序后的数组。
    对于这道题:
    1操作:
    就将两头的暴力加并重置该区间的b[],中间的打个标记完事儿~
    2操作:
    我们可以将将二分答案将问题转化成判定,对于二分出来的mid:
    我们在[l,r]这个区间中,
    左右两头的依旧暴力搞,中间的就区间二分嘛,用之前的那个排了序的数组。
    嗯嗯,就这样子切掉了~~~(nice!)
    但之前WA0了一次。。。↓

    主要是二分时候的判断语句有问题(详见标)

    上标:

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define N 80010
    using namespace std;
    int n,a[N],t,l,r,x,st,q;
    int bl[N],le[N],ri[N],b[N],pl[N];
    
    inline int read()
    {
    	int x=0,f=0; char c=getchar();
    	while (c<'0' || c>'9') f=(c=='-') ? 1:f,c=getchar();
    	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return f ? -x:x;
    }
    
    void init()
    {
    	for (int i=1;i<=bl[n];i++)
    		sort(b+le[i],b+ri[i]+1);
    }
    
    void reset(int x)
    {
    	for (int i=le[x];i<=ri[x];i++) b[i]=a[i]=a[i]+pl[x];
    	pl[x]=0;sort(b+le[x],b+ri[x]+1);
    }
    
    void change(int l,int r,int add)
    {
    	if (bl[l]==bl[r])
    	{
    		for (int i=l;i<=r;i++) a[i]+=add;
    		reset(bl[l]); return;
    	}
    	for (int i=l;i<=ri[bl[l]];i++) a[i]+=add;
    	reset(bl[l]);
    	for (int i=le[bl[r]];i<=r;i++) a[i]+=add;
    	reset(bl[r]);
    	for (int i=bl[l]+1;i<bl[r];i++) pl[i]+=add;
    }
    
    int erfen(int x,int num)
    {
    	int z=le[x],y=ri[x],mid;
    	while (z<=y)
    	{
    		mid=z+y>>1;
    		if (b[mid]<=num) z=mid+1;//这里是b[mid]<=num,我一开始打成了b[mid]<num!主要还是懒。。。
    		else y=mid-1;
    	}
    	return z-le[x];
    }
    
    int check(int l,int r,int x)
    {
    	int s=0;
    	if (bl[l]==bl[r])
    	{
    		for (int i=l;i<=r;i++)
    			s+=(a[i]+pl[bl[l]]<=x);
    		return s;
    	}
    	for (int i=l;i<=ri[bl[l]];i++)
    		s+=(a[i]+pl[bl[l]]<=x);
    	for (int i=le[bl[r]];i<=r;i++)
    		s+=(a[i]+pl[bl[r]]<=x);
    	for (int i=bl[l]+1;i<bl[r];i++)
    	{
    		s+=erfen(i,x-pl[i]);
    	}
    	return s;
    }
    
    void find(int l,int r,int x)
    {
    	int ll=-5000000,rr=5000000,mid;
    	while (ll<=rr)
    	{
    		mid=ll+rr>>1;
    		if (check(l,r,mid)<x) ll=mid+1;
    		else rr=mid-1;
    	}
    	printf("%d
    ",ll);
    }
    
    int main()
    {
    	freopen("4438.in","r",stdin);
    	freopen("4438.out","w",stdout);
    	n=read(),st=sqrt(n);
    	for (int i=1;i<=n;i++)
    	{
    		a[i]=b[i]=read(),bl[i]=(i-1)/st+1;
    		if (!le[bl[i]]) le[bl[i]]=i,ri[bl[i-1]]=i-1;
    	}
    	ri[bl[n]]=n;
    	init();
    	q=read();
    	while (q--)
    	{
    		t=read(),l=read(),r=read(),x=read();
    		if (t==1) change(l,r,x);
    		else find(l,r,x);
    	}
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    Linux Vim编辑器
    Linux sed 流编辑器
    Shell 编程 (变量和条件测试)
    Linux 下 Bash配置文件读取
    Linux 用户、权限
    Linux 指令(一)文件/目录操作
    Ubuntu 下安装 Swoole
    Mysql IN语句查询
    Mysql 查询优化
    Mysql 获取表属性
  • 原文地址:https://www.cnblogs.com/jz929/p/11817566.html
Copyright © 2020-2023  润新知