HDU 4417 Super Mario (树状数组+离线处理)(划分树+二分答案)
来源:互联网 发布:php简单分页代码 编辑:程序博客网 时间:2024/05/23 14:25
题意: 给定1--n区间,有q个询问,询问l,r,k表示区间[l,r]小于等于k的数的个数
思路: 可以用划分树(求区间第k大值)变形一下,来求小于等于k的个数,但是此题直接离线处理询问高效的多。
首先将1--n区间的值记录位置,从小到大排序,每个询问按照k值从小到大排序,然后从小到大开始,根据查询的H,将满足条件的的点插入,计数+1,然后就是求区间和。
#include <iostream>#include <algorithm>#include <cmath>#include<functional>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#include <climits>//形如INT_MAX一类的#define MAX 100001using namespace std;inline void RD(int &ret) { char c; do { c = getchar(); } while(c < '0' || c > '9') ; ret = c - '0'; while((c=getchar()) >= '0' && c <= '9') ret = ret * 10 + ( c - '0' );}void OT(int a) { if(a >= 10)OT(a / 10); putchar(a % 10 + '0');}int n,q;struct node { int v,id;} a[MAX];int c[MAX];struct QES { int l,r,h,id;} qes[MAX];int ans[MAX];bool cmp(const node &a, const node &b) { return a.v < b.v;}bool cmp2(const QES &a, const QES &b) { return a.h < b.h;}int lowbit(int x) { return x & (-x);}void update(int x,int va) { while(x <= n) { c[x] += va; x += lowbit(x); }}int query(int x) { int ans = 0; while(x > 0) { ans += c[x]; x -= lowbit(x); } return ans;}int main() { int T; cin >> T; int ca = 1; while(T--) { RD(n); RD(q); memset(c,0,sizeof(c)); for(int i=1; i<=n; i++) { RD(a[i].v); a[i].id = i; } sort(a+1,a+1+n,cmp); for(int i=0; i<q; i++) RD(qes[i].l),RD(qes[i].r),RD(qes[i].h),qes[i].id = i; sort(qes,qes+q,cmp2); int order = 1; for(int i=0; i<q; i++) { while(a[order].v <= qes[i].h && order <= n) { update(a[order].id,1); order ++; } ans[qes[i].id] = query(qes[i].r+1) - query(qes[i].l); } printf("Case %d:\n",ca++); for(int i=0; i<q; i++)OT(ans[i]),puts(""); } return 0;}
划分树:
要求的是小于等于k的个数,可以二分该个数mid,找到的也是第mid小的值,与k大小比较,直到得到答案
#include <iostream>#include <algorithm>#include <cmath>#include<functional>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#include <climits>//形如INT_MAX一类的#define MAX 100005#define INF 0x7FFFFFFF#define L(x) x << 1#define R(x) x << 1 | 1using namespace std;struct Seg_Tree { int l,r,mid;} tr[MAX*4];int sorted[MAX];int lef[20][MAX];int val[20][MAX];void build(int l,int r,int step,int x) { tr[x].l = l; tr[x].r = r; tr[x].mid = (l + r) >> 1; if(tr[x].l == tr[x].r) return ; int mid = tr[x].mid; int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左边的 for(int i = l ; i <= r ; i ++) { if(val[step][i] < sorted[mid]) { lsame --;//先假设左边的数(mid - l + 1)个都等于val_mid,然后把实际上小于val_mid的减去 } } int lpos = l; int rpos = mid + 1; int same = 0; for(int i = l ; i <= r ; i ++) { if(i == l) { lef[step][i] = 0;//lef[i]表示[ tr[x].l , i ]区域里有多少个数分到左边 } else { lef[step][i] = lef[step][i-1]; } if(val[step][i] < sorted[mid]) { lef[step][i] ++; val[step + 1][lpos++] = val[step][i]; } else if(val[step][i] > sorted[mid]) { val[step+1][rpos++] = val[step][i]; } else { if(same < lsame) {//有lsame的数是分到左边的 same ++; lef[step][i] ++; val[step+1][lpos++] = val[step][i]; } else { val[step+1][rpos++] = val[step][i]; } } } build(l,mid,step+1,L(x)); build(mid+1,r,step+1,R(x));}int query(int l,int r,int k,int step,int x) { if(l == r) { return val[step][l]; } int s;//s表示[l , r]有多少个分到左边 int ss;//ss表示 [tr[x].l , l-1 ]有多少个分到左边 if(l == tr[x].l) { s = lef[step][r]; ss = 0; } else { s = lef[step][r] - lef[step][l-1]; ss = lef[step][l-1]; } if(s >= k) {//有多于k个分到左边,显然去左儿子区间找第k个 int newl = tr[x].l + ss; int newr = tr[x].l + ss + s - 1;//计算出新的映射区间 return query(newl,newr,k,step+1,L(x)); } else { int mid = tr[x].mid; int bb = l - tr[x].l - ss;//bb表示 [tr[x].l , l-1 ]有多少个分到右边 int b = r - l + 1 - s;//b表示 [l , r]有多少个分到右边 int newl = mid + bb + 1; int newr = mid + bb + b; return query(newl,newr,k-s,step+1,R(x)); }}int n,m;int main() { int T; cin >> T; int l,r,k; int ca = 1; while(T--) { scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&val[0][i]); sorted[i] = val[0][i]; } sort(sorted+1,sorted+1+n); build(1,n,0,1); printf("Case %d:\n",ca++); for(int i=0; i<m; i++) { scanf("%d%d%d",&l,&r,&k); l ++; r ++; int ll = 1; int rr = r - l + 1; int mid,maxx = 0; while(ll <= rr) { mid = (ll + rr) >> 1; if(query(l,r,mid,0,1) <= k) { maxx = max(maxx,mid); ll = mid + 1; } else rr = mid - 1; } printf("%d\n",maxx); } } return 0;}
- HDU 4417 Super Mario (树状数组+离线处理)(划分树+二分答案)
- hdu 4417 Super Mario(离线树状数组|划分树)
- hdu 4417 Super Mario(划分树或树状数组)
- HDU 4417 Super Mario(树状数组离线处理 or 主席树)
- HDU 4417 Super Mario (树状数组、离线处理)
- HDU 4417 Super Mario--离线树状数组、划分树、线段树
- HDU 4417 Super Mario 划分树/树状数组
- HDU 4417 Super Mario (树状数组 + 离线)
- HDU 4417 - Super Mario (求区间小于h的数 划分树 二分 线段树 树状数组)
- HDU 4417 Super Mario(线段树||树状数组+离线操作 之树状数组篇)
- HDU 4417 —— Super Mario(树状数组,离散化,离线处理)
- hdu 4417 Super Mario--二分--划分树
- HDU 4417 Super Mario(划分树+二分)
- HDU-4417-Super Mario(划分树+二分)
- 【划分树+二分】HDU 4417 Super Mario
- HDU 4417Super Mario 划分树 + 二分
- HDU 4417 Super Mario 划分树+二分
- HDU-4417 Super Mario,划分树+二分!
- 阻塞、非阻塞、同步、异步浅析
- 卫计委:全面推进免费孕前优生健康检查全覆盖
- 绑定远程服务
- Android 百度地图开发(一)--- 申请API Key和在项目中显示百度地图
- Protocol Buffers定义协议格式
- HDU 4417 Super Mario (树状数组+离线处理)(划分树+二分答案)
- gsoap工具生成soap.h.cpp文件遇到的问题
- C# 转义字符
- 在AIX环境下安装IBM JDK 1.6的教程
- Opencv中Mat数据访问方式效率对比分析
- netfilter
- Ubuntu下将vim配置为Python IDE
- jdbcTemplate获得数据库生成的主键值
- 编程实现Android模拟器中窗口截图存成文件