题目链接:点击查看

题目大意:给出由 n 个数的数列,再给出 m 次查询,每次查询需要输出 [ l , r ] 内小于等于 h 的数有多少个

题目分析:大晚上睡不着觉随便做做题,发现这个题目原来可以用主席树来做,又发现这个题目去年暑假竟然没写博客,于是补上一发

线段树离线的做法就是对数列和询问的高度排序,遍历每个询问,双指针将小于等于当前询问高度的位置都扔到线段树中,记录当前询问的区间内有多少个数即可

主席树在线做法,有两种,先说一下网上最常见的,就是遍历每个位置作为下标,对于下标维护可持久化线段树,每个权值线段树维护的是高度信息,记录一下每个高度出现了多少次,答案显然就是第 R 个版本中 [ 1 , h ] 的个数减去第 L - 1 个版本中 [ 1 , h ] 的个数了

再说一下我自己的做法,我是对于高度维护了可持久化线段树,每个权值线段树维护的是区间信息,记录一下 [ 1 , h ] 内的所有数在区间上的分布情况,这样答案就是第 h 个版本的权值线段树中 [ l , r ] 中有多少个数了

两种主席树的做法时空复杂度相同且都是需要进行离散化的,但我个人感觉自己的做法更好理解一些,更能体现了:主席树是可持久化线段树,其中每个版本的主席树单独拿出来都是一个权值线段树

代码:

主席树:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;struct Node
{int l,r;int sum;
}tree[N*20];int cnt,root[N];void update(int num,int &k,int l,int r)
{tree[cnt++]=tree[k];k=cnt-1;tree[k].sum++;if(l==r)return;int mid=l+r>>1;if(num<=mid)update(num,tree[k].l,l,mid);elseupdate(num,tree[k].r,mid+1,r);
}int query(int k,int l,int r,int L,int R)//[l,r]:目标区间,[L,R]:当前区间
{if(R<l||L>r)return 0;if(L>=l&&R<=r)return tree[k].sum;int mid=L+R>>1;return query(tree[k].l,l,r,L,mid)+query(tree[k].r,l,r,mid+1,R);
}map<int,vector<int>>mp;vector<int>node;int get_id(int x)
{return upper_bound(node.begin(),node.end(),x)-node.begin();
}void discreate()
{sort(node.begin(),node.end());node.erase(unique(node.begin(),node.end()),node.end());
}void init()
{mp.clear();node.clear();root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1;
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int w;cin>>w;int kase=0;while(w--){init();int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int h;scanf("%d",&h);mp[h].push_back(i);node.push_back(h);}discreate();for(int i=1;i<=node.size();i++)//按照高度建主席树,每个高度的前缀和的权值线段树代表的是[1,h]内的高度在[1,n]上的分布情况 {root[i]=root[i-1];for(int pos:mp[node[i-1]])update(pos,root[i],1,n);}printf("Case %d:\n",++kase);while(m--){int l,r,h;scanf("%d%d%d",&l,&r,&h);l++,r++;printf("%d\n",query(root[get_id(h)],l,r,1,n));}}return 0;
}

离线+线段树:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<sstream>
#include<cmath>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;struct Tree
{int l,r,sum;
}tree[N<<2];struct Node
{int hei,pos;bool operator<(Node a)const{return hei<a.hei;}
}a[N];struct node
{int hei,l,r,id;bool operator<(node a)const{return hei<a.hei;}
}b[N];int ans[N];void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].sum=0;if(l==r)return;int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}void update(int k,int pos)
{if(tree[k].l==tree[k].r){tree[k].sum=1;return;}int mid=(tree[k].l+tree[k].r)>>1;if(mid>=pos)update(k<<1,pos);elseupdate(k<<1|1,pos);tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}int query(int k,int l,int r)
{if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].sum;return query(k<<1,l,r)+query(k<<1|1,l,r);
}int main()
{
//  freopen("input.txt","r",stdin);int w;cin>>w;int kase=0;while(w--){int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i].hei);a[i].pos=i;}for(int i=1;i<=m;i++){scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].hei);b[i].l++;b[i].r++;b[i].id=i;}build(1,1,n);sort(a+1,a+1+n);sort(b+1,b+1+m);int pos=1;for(int i=1;i<=m;i++){int h=b[i].hei;while(a[pos].hei<=h){update(1,a[pos].pos);pos++;}ans[b[i].id]=query(1,b[i].l,b[i].r);}printf("Case %d:\n",++kase);for(int i=1;i<=m;i++)cout<<ans[i]<<endl;}return 0;
}

HDU - 4417 Super Mario(主席树/线段树+离线)相关推荐

  1. #HDU 4417 Super Mario (主席树 + 二分)

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  2. HDU 4417 Super Mario(莫队 + 树状数组 + 离散化)

    Super Mario 思路 区间查找问题,容易想到离线莫队,确实这题就是莫队,接下来我们考虑如何维护区间高度值问题. 既然是离线嘛,我们容易想到离散化和他挂钩,想想这题是否需要离散化,高度的最大值是 ...

  3. HDU 4417 Super Mario(线段树离线处理/主席树)

    Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...

  4. hdu 4417 Super Mario 树状数组||主席树

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Prob ...

  5. HDU 4417 Super Mario(线段树)

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  6. hdu 4417 Super Mario(可持久化线段树)

    题意:给你一些数,有多次询问,问你在l,r区间内小于k的数有多少个 思路:主席树大发好,虽然树状数组和线段树离线也可以做 代码: #include <set> #include <m ...

  7. HDU 4417 Super Mario(线段树||树状数组+离线操作 之线段树篇)

    Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...

  8. HDU 4417 Super Mario(离线线段树or树状数组)

    Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping ...

  9. HDU 4417 Super Mario(划分树)

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

最新文章

  1. 五年级上册计算机课如何拉表格,川教版小学信息技术五年级上册第八课 调整表格...
  2. 统计寄存器AX中1 的个数
  3. Delphi Form Designer (窗体设计器)之二
  4. python保存代码_python入门(5)使用文件编辑器编写代码并保存执行
  5. android 集成x5内核时 本地没有,腾讯浏览服务-接入文档
  6. 汉字与区位码互转(转)
  7. PHP数组常用方法(优化版)
  8. 大学数学实验习题--统计推断 (附答案)判断alpha,n与mu,sigma的估计区间长度的关系
  9. 推荐的开源 PHP CMS 系统
  10. error: You must be logged in to the server (Unauthorized)报错处理
  11. 基于MATLAB的一维条码二维码识别
  12. PHP实战项目(仿糯米网)
  13. LOL手游登上去服务器维护,lol手游进不去怎么回事?无法登陆解决方法
  14. Qt error: C2039: “staticMetaObject”: 不是“QXXX”的成员
  15. HTML 网页打印实现分页打印功能
  16. fails sanity check错误的解决方法
  17. 八款好用的浏览器兼容性测试工具推荐
  18. 计算机技术复试面试英语自我介绍,计算机复试英语自我介绍
  19. Flutter 如何监听页面在前台还是后台
  20. Retinex图像增强

热门文章

  1. db2界面调用存储过程_第三章 操作系统用户界面
  2. 为何excel中数据无法计算机,excel表格内数据为何无法计算机-为什么EXCEL单元格内的数字不能运算...
  3. OpenResty请求参数处理
  4. ReentrantLock重入锁
  5. 策略模式Strategy Pattern应用场景
  6. 日志规范之了解slf4j
  7. 多租户以及基于多租户的数据库设计需求
  8. 数据库-优化-数据库结构的优化-拆分优化
  9. 注册中心解决了什么问题
  10. Oracle之用户操作