hdu 4417 Super Mario(划分树或树状数组)

2023-12-05 21:32

本文主要是介绍hdu 4417 Super Mario(划分树或树状数组),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题意:给你n个数,m个查询,对于一个查询问在[a,b]范围内小于c的数有多少个。

有两种做法:1 树状数组离线处理,将输入的n个数按大小排序,也将查询按他们查询的数的大小排序。从小到大到这n个数放进数状数组里,当小于一个查询的c的所有的数都在放进数状数组里面的时候,查询[a,b]范围内有多少个数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+5;
struct node
{int valu,ind;node(){}node(int a,int b){valu=a;ind=b;}bool operator<(const node &b)const{return valu<b.valu;}
};
struct Query
{int st,ed,valu,ind;Query(){}Query(int a,int b,int c,int d){st=a;ed=b;valu=c;ind=d;}bool operator<(const Query &b)const{return valu<b.valu;}
};
struct BIT
{int a[N];int lowbit(int x){return x&(-x);}void clear() {memset(a,0,sizeof(a));}void updata(int pos){for(int i=pos;i>0;i-=lowbit(i))a[i]+=1;}int query(int st,int ed){int sum=0;for(int i=st;i<N;i+=lowbit(i))sum+=a[i];for(int i=ed+1;i<N;i+=lowbit(i))sum-=a[i];return sum;}
}bit;int res[N];
vector<node> data;
vector<Query> op;int main()
{int t,t_cnt=0;scanf("%d",&t);while(t--){op.clear(); data.clear(); bit.clear();int n,m,a,b,c;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a);data.push_back(node(a,i));}for(int i=0;i<m;i++){scanf("%d%d%d",&a,&b,&c);op.push_back(Query(a+1,b+1,c,i));}sort(data.begin(),data.end());sort(op.begin(),op.end());int ind=0;for(int i=0;i<(int)data.size();i++){while(ind<(int)op.size()&&op[ind].valu<data[i].valu) {res[op[ind].ind]=bit.query(op[ind].st,op[ind].ed);ind++;}bit.updata(data[i].ind);}for(int i=ind;i<(int)op.size();i++)res[op[i].ind]=bit.query(op[i].st,op[i].ed);printf("Case %d:\n",++t_cnt);for(int i=0;i<m;i++)printf("%d\n",res[i]);}return 0;
}
第二种做法是划分树。对于每个查询,二分区间里的第k大数,找出大于要查询的c的第一个数的是第k大,那么答案就是这个k-1。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MID(a,b) (a+((b-a)>>1))
const int N=1e5+5;
struct P_Tree
{int n,order[N];int valu[20][N],num[20][N];void init(int len){n=len;for(int i=0;i<20;i++) valu[i][0]=0,num[i][0]=0;for(int i=1;i<=n;i++){scanf("%d",&order[i]);valu[0][i]=order[i];}sort(order+1,order+1+n);build(1,n,0);}void build(int lft,int rht,int ind){if(lft==rht) return;int mid=MID(lft,rht);int ln=lft,rn=mid+1,same=mid-lft+1;for(int i=lft;i<=rht;i++)if(valu[ind][i]<order[mid]) same--;for(int i=lft;i<=rht;i++){int flag=0;if((valu[ind][i]<order[mid])||(valu[ind][i]==order[mid]&&same)){flag=1;valu[ind+1][ln++]=valu[ind][i];if(valu[ind][i]==order[mid]) same--;}else valu[ind+1][rn++]=valu[ind][i];num[ind][i]=num[ind][i-1]+flag;}build(lft,mid,ind+1);build(mid+1,rht,ind+1);}int query(int st,int ed,int k,int lft,int rht,int ind){if(k==0) return -1;if(ed-st+1<k) return (1<<30);if(lft==rht) return valu[ind][lft];int mid=MID(lft,rht);int lx=num[ind][st-1]-num[ind][lft-1];int ly=num[ind][ed]-num[ind][st-1];int rx=st-1-lft+1-lx;int ry=ed-st+1-ly;if(ly>=k) return query(lft+lx,lft+lx+ly-1,k,lft,mid,ind+1);else{st=mid+1+rx;ed=mid+1+rx+ry-1;return query(st,ed,k-ly,mid+1,rht,ind+1);}}
}tree;
int main()
{int t,t_cnt=0;scanf("%d",&t);while(t--){int n,m;scanf("%d%d",&n,&m);tree.init(n);printf("Case %d:\n",++t_cnt);for(int i=0;i<m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);a++; b++;int lft=0,rht=b-a+2;while(lft<rht){int mid=MID(lft,rht);int ele=tree.query(a,b,mid,1,n,0);if(ele<=c) lft=mid+1;else rht=mid;}printf("%d\n",lft-1);}}
}


这篇关于hdu 4417 Super Mario(划分树或树状数组)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/459222

相关文章

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que