首页 > 其他分享 >统计数量(分块+二分)

统计数量(分块+二分)

时间:2024-03-12 15:33:58浏览次数:26  
标签:二分 分块 int d% mid ++ ans 统计

第1题     统计数量 查看测评数据信息

给一个长度是n的正整数数组,a[1],a[2],a[3],...a[n-1],a[n], 其中1<=a[i]<=1000。现在在数组a上进行m次 操作:

1.M x y z, 表示对a数组的闭区间[x,y]内所有a[i]的值分别加上z

2.A x y zz, 询问a数组闭区间[x,y]内有多少a[i]的值大于等于zz

输入格式

 

第一行两个整数n,m

接下来一行n个整数,表示a[1],a[2],a[3],...a[n-1],a[n]

接下来m个询问:

若第一个字母为M,则紧接着有三个数字x,y,z

若第一个字母为A,则紧接着有三个数字x,y,zz

部分数据 n<=1000, m<=1000

100%的数据 n<=1e6, m<=3000, 1<=z<=1000, 1<=zz<=1e9

 

输出格式

 

对每个A询问输出一行,仅含一个整数,表示闭区间[x,y]内大于等于zz的a[i]的个数。

 

输入/输出例子1

输入:

5 3

1 2 3 4 5

A 1 5 4

M 3 5 1

A 1 5 4

 

输出:

2

3

 

样例解释

    原题:https://www.luogu.com.cn/problem/P2801     注意操作二 区间数大于等于某个数
int query(int L, int R, int d)
{
	int ans=0;
	for (int i=L; i<=R; i++)
		if (a[i]+add[pos[i]]>=d) ans++;
	return ans;
}

查找的时候可以考虑暴力,但这样肯定会超时,不妨考虑查找元素时用二分,

例如3,4,5,6,6,7,7,8,我要找>=5的数的个数

只要找第一个<5的数的位置,便可以得出>=5的数的个数

 

也是用分块思想,中间段二分,两边二分即可

int query(int L, int R, int k)
{
	int p=pos[L], q=pos[R], ans=0;
	if (p==q)
	{
		for (int i=L; i<=R; i++) 
			if (a[i]+add[p]>=k) ans++;
	}
	else
	{
		for (int i=L; i<=ed[p]; i++) 
			if (a[i]+add[p]>=k) ans++;
		for (int i=st[q]; i<=R; i++) 
			if (a[i]+add[q]>=k) ans++;
			
//中间段二分 for (int i=p+1; i<=q-1; i++) { int L=st[i], R=ed[i], res=0; while (L<=R) { int mid=L+R>>1; if (d[mid]+add[i]>=k) { R=mid-1;//因为要找<k的,尝试调整右端点 res=ed[i]-mid+1; //记得+1 } else L=mid+1; } ans+=res; } } return ans; }

 

但是要注意,这里原先的数组是无序的,所以要新开一个数组存着有序的数列

 

 

 

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=1e6+5;
int n, m, a[N], d[N], st[N], ed[N], pos[N], add[N];
char op;
int x, y, k;
void init()
{
	int block=sqrt(n);
	int t=n/block;
	
	if (n%block) t++;
	
	for (int i=1; i<=t; i++)
	{
		st[i]=(i-1)*block+1;
		ed[i]=i*block;
	}
    ed[t]=n;
	for (int i=1; i<=n; i++) d[i]=a[i], pos[i]=(i-1)/block+1;
	
	for (int i=1; i<=t; i++)
		sort(d+st[i], d+ed[i]+1);
}
void Add(int L, int R, int k)
{
	int p=pos[L], q=pos[R];
	if (p==q)
	{
		for (int i=L; i<=R; i++) a[i]+=k;
		for (int i=st[p]; i<=ed[p]; i++) d[i]=a[i];
		sort(d+st[p], d+ed[p]+1);
	}
	else
	{
		for (int i=p+1; i<=q-1; i++) add[i]+=k;
		
		for (int i=L; i<=ed[p]; i++) a[i]+=k;
		for (int i=st[p]; i<=ed[p]; i++) d[i]=a[i];
		sort(d+st[p], d+ed[p]+1);
		
		for (int i=st[q]; i<=R; i++) a[i]+=k;
		for (int i=st[q]; i<=ed[q]; i++) d[i]=a[i];
		sort(d+st[q], d+ed[q]+1);
	}
}
int query(int L, int R, int k)
{
	int p=pos[L], q=pos[R], ans=0;
	if (p==q)
	{
		for (int i=L; i<=R; i++) 
			if (a[i]+add[p]>=k) ans++;
	}
	else
	{
		for (int i=L; i<=ed[p]; i++) 
			if (a[i]+add[p]>=k) ans++;
		for (int i=st[q]; i<=R; i++) 
			if (a[i]+add[q]>=k) ans++;
			
		for (int i=p+1; i<=q-1; i++) 
		{
			int L=st[i], R=ed[i], res=0;
			while (L<=R)
			{
				int mid=L+R>>1;
				if (d[mid]+add[i]>=k) 
				{
					R=mid-1;
					res=ed[i]-mid+1;
				}
				else L=mid+1;
			}
			ans+=res;
		}
	}
	return ans; 
}
signed main()
{
	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; i++) scanf("%lld", &a[i]);
	init();
	
	while (m--)
	{
		cin>>op;
		if (op=='M')
		{
			scanf("%d%d%lld", &x, &y, &k);
			Add(x, y, k);
		}
		else if (op=='A')
		{
			scanf("%d%d%lld", &x, &y, &k);
			printf("%lld\n", query(x, y, k));
		}
	}
	return 0;
}

  

标签:二分,分块,int,d%,mid,++,ans,统计
From: https://www.cnblogs.com/didiao233/p/18068427

相关文章

  • 分块
    与线段树类似。是暴力的优化版,详细见下两个链接https://www.cnblogs.com/milky-w/p/8447724.htmlhttps://www.cnblogs.com/Miracevin/p/9403620.html  板子:#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=1e5+5;intn,m,a[N],s......
  • 7-3 jmu-python-统计字符个数
    输入一个字符串,统计其中数字字符及小写字符的个数输入格式:输入一行字符串输出格式:共有?个数字,?个小写字符,?填入对应数量输入样例:helo134ss12输出样例:共有5个数字,6个小写字符代码长度限制16KB时间限制400ms内存限制64MB#读取一行字......
  • Linux常用统计命令大全
    简介Linux系统作为一种常用的操作系统,具有丰富的命令行工具,其中包括了许多用于统计数据的命令。这些命令可以帮助系统管理员和开发人员轻松地分析和处理数据。本文将介绍一些常用的Linux统计命令,帮助读者更好地理解和使用它们。grepgrep命令用于在文本文件中搜索指定模式的文......
  • Mysql和Clickhouse数据查询-按照时间分组统计并且对无无数据的日期补0
      最近在做数据查询需求的时候,遇到按照时间分组查询统计指标的需求,比如说查询模块的最近15天访问数据量,没有数据的日期补0,以前对于这种类似的需求都是通过代码来补数据,想试试sql实现这种查询,因此查询了不少文章,对于类似实现方法的文章网上也有很多,差异也很多,因此这篇文章只......
  • POJ--3258 River Hopscotch(二分搜索/最大化最小值)
    记录10:232023-3-11http://poj.org/problem?id=3259二分法查找最大的可能解,检查x是否符合条件(当前这个位置上的值-前上一个选取位置的值>=x)注意的点:使用了[begin,end)的左闭右开区间,所以结果要begin-1,end要从L+1开始算点击查看代码intL,N,M;introcks[5......
  • 蓝桥杯算法集训 - Week1:二分、前缀和、差分算法
    蓝桥杯算法集训-Week1本系列随笔用于整理AcWing题单——《蓝桥杯集训·每日一题2024》的系列题型及其对应的算法模板。一、二分查找二分算法原理复习参考:二分查找-Hello算法Ⅰ、二分模板boolcheck(intx){/*...*/}//检查x是否满足某种性质//区间[l,r]被划分......
  • 第一节二分
    第一节:二分定义:(一遍恒比这个值小一遍恒比这个值大为了找出这个值第一次或最后一次出现的位置所以用二分)注意,这里的有序是广义的有序,如果一个数组中的左侧或者右侧都满足某一种条件,而另一侧都不满足这种条件,也可以看作是一种有序(如果把满足条件看做 ,不满足看做 ,至少对于这个条......
  • 统计语言模型
    2024.3.8统计语言模型统计语言模型1.语言模型语言(人说的话)+模型(表示某个东西,完成某个任务)P1(“判断这个词的词性”),P2(“判断这个词的磁性”)**“判断这个词的"**2.统计语言模型用统计的方法去解决上述两个问题“判断这个词的词性”="判断","这个",”词“,”的......
  • 分块小结
    分块概念就是把一个长序列分成\(\sqrt{n}\)个区间,分别维护每个区间内的信息和,然后查询时可以优化时间复杂度。还可以完成一些线段树完成不了的神秘操作,比如这道题。但是总体时间复杂度不如线段树,但它的扩展性比线段树还要强,因为分块中每个区间的信息和不需要具有传递性。怎......
  • abc309E 统计家族中已买保险的人数
    一个有n个成员的家族构成一棵树,1为树根。有m份保险,第i份保险为x[i]以及他的y[i]代以内的所有子孙购买。问总共有多少人有保险。数据范围:1<=n,m<=3e5思路:dfs遍历统计即可,y值需要向下传递,-1表示未买。#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defi......