HDU 4417 - Super Mario ( 划分树+二分 / 树状数组+离线处理+离散化)
题意:给一个数组,每次询问输出在区间[L,R]之间小于H的数字的个数。
此题可以使用划分树在线解决。
划分树可以快速查询区间第K小个数字。逆向思考,判断小于H的最大的一个数字是区间第几小数,即是答案。这一步可以使用二分搜索上界。时间复杂度是O(logn*logn)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
#define MAXN 100005
using namespace std;
struct Divide_Tree
{
][MAXN];
][MAXN];
void build(int c,int L,int R)
{
,lsame=mid+-L,lp=L,rp=mid+;
for(int i=L; i<mid; ++i)
if(sorted[i]<sorted[mid]) lsame--;
for(int i=L; i<=R; ++i)
{
;
];
if(dat[c][i]<sorted[mid])
{
dat[c+][lp++]=dat[c][i];
toleft[c][i]++;
}
else if(dat[c][i]>sorted[mid])
dat[c+][rp++]=dat[c][i];
else
{
if(lsame)
{
lsame--;
toleft[c][i]++;
dat[c+][lp++]=sorted[mid];
}
][rp++]=sorted[mid];
}
}
if(L==R) return ;
build(c+,L,mid);
build(c+,mid+,R);
}
int query(int c,int L,int R,int ql,int qr,int k)
{
if(L==R) return dat[c][L];
;
int la,lb,ra,rb;
;
];
lb=toleft[c][qr];
ra=ql-L-la;
rb=qr+-L-lb;
int s=lb-la;
,L,mid,L+la,L+lb-,k);
,mid+,R,mid++ra,mid+rb,k-s);
}
};
Divide_Tree tree;
int n;
int Bsearch(int low,int high,int key,int ql,int qr)
{
)>>;
while(low<high)
{
,,n,ql,qr,mid)<=key) low=mid;
;
mid=(low+high+)>>;
}
,,n,ql,qr,mid)<=key) return mid;
;
}
int main()
{
;
int q;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
; i<=n; ++i)
{
scanf("%d",&tree.arr[i]);
tree.sorted[i]=tree.dat[][i]=tree.arr[i];
}
sort(tree.sorted+,tree.sorted+n+);
tree.build(,,n);
int l,r,k;
printf("Case %d:\n",++kase);
while(q--)
{
scanf("%d%d%d",&l,&r,&k);
l++;
r++;
,r-l+,k,l,r);
) printf("0\n");
else printf("%d\n",p);
}
}
;
}
另外,此题有更高效的算法。 未完待续。
此题也可以离线解决。
首先考虑单次查询整个区间小于某个数的数字个数的思路,我们可以统计每个数字出现的次数,然后利用前缀和快速计算小于该数的数字个数。
如果是查询部分区间[L,R]小于某数x的数字个数的话,答案为 区间[1,R]小于x的数字个数 减去 区间[1,L-1]小于x的数字个数。那么如何计算区间[1,S]内小于x的数字个数呢。
每出现一个数字v就在第v个位置加一即可。统计小于x的数字个数即计算前x个位置的和,这里需要求和,也用到了修改,显然用树状数组更高效。这样当枚举到第i个数字时,求区间[1,i]内小于x的数字个数即此时计算前x个数字的和。
由于这里数字较大,数组下标存不下,所以需要离散化。
#include<iostream>
#include<vector>
#include<cstring>
#include<map>
#include<cstdio>
#include<algorithm>
#define MAXN 100005
using namespace std;
int n,m,cn;
map<int,int> has;
struct BIT
{
int dat[MAXN];
void clear()
{
memset(dat,,sizeof(dat));
}
int lowbit(int x)
{
return -x&x;
}
void add(int x,int v)
{
while(x<=cn)
{
dat[x]+=v;
x+=lowbit(x);
}
}
int sum(int x)
{
;
)
{
s+=dat[x];
x-=lowbit(x);
}
return s;
}
};
struct Segment
{
int num,left,right,high;
int presum,ans;
Segment (int a,int b,int c,int d):num(a),left(b),right(c),high(d) {}
bool operator < (const Segment &p) const
{
return left<p.left;
}
};
bool cmp(Segment a,Segment b)
{
return a.num<b.num;
}
vector<Segment> vec;
vector<int> numb;
int arr[MAXN];
vector<int> posL[MAXN],posR[MAXN];
BIT tree;
int main()
{
int T;
scanf("%d",&T);
;
while(T--)
{
scanf("%d%d",&n,&m);
numb.clear();
; i<=n; ++i)
{
scanf("%d",&arr[i]);
numb.push_back(arr[i]);
posL[i+].clear();
posR[i+].clear();
}
vec.clear();
; i<m; ++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
numb.push_back(z);
vec.push_back(Segment (i,x,y,z));
}
sort(vec.begin(),vec.end());
; i<vec.size(); ++i)
{
posL[vec[i].left].push_back(i);
posR[vec[i].right].push_back(i);
}
has.clear();
cn=;
sort(numb.begin(),numb.end());
; i<numb.size(); ++i)
if(!has[numb[i]]) has[numb[i]]=++cn;
tree.clear();
; i<=n; ++i)
{
; j<posL[i].size(); ++j)
{
int u=posL[i][j];
int v=has[vec[u].high];
vec[u].presum=tree.sum(v);
}
tree.add(has[arr[i]],);
; j<posR[i].size(); ++j)
{
int u=posR[i][j];
int v=has[vec[u].high];
vec[u].ans=tree.sum(v)-vec[u].presum;
}
}
sort(vec.begin(),vec.end(),cmp);
printf("Case %d:\n",++kase);
; i<vec.size(); ++i)
printf("%d\n",vec[i].ans);
}
;
}
离线的另一种思路。
我们可以按照每个数的大小顺序插入到树状数组中,同时按照高度的大小顺序查询。
这样将所有数和高度一起存入数组并从小到大排序。这样遇到数就在树状数组该数字的位置加一,遇到查询就对该区间求和,这样可以保证在查询的时候树状数组上被插入的数都是小于x的。
注意,排序的时候如果数的大小和查询高度大小一样,则查询放在后面。
#include<iostream>
#include<vector>
#include<cstring>
#include<map>
#include<cstdio>
#include<algorithm>
#define MAXN 100005
using namespace std;
int n,m;
struct BIT
{
int dat[MAXN];
void clear()
{
memset(dat,,sizeof(dat));
}
int lowbit(int x)
{
return -x&x;
}
void add(int x,int v)
{
while(x<=n)
{
dat[x]+=v;
x+=lowbit(x);
}
}
int sum(int x)
{
;
)
{
s+=dat[x];
x-=lowbit(x);
}
return s;
}
};
struct Segment
{
int num,dat,left,right;
int ans;
Segment(,,,):num(a),dat(b),left(c),right(d) {}
bool operator <(const Segment &p) const
{
return dat<p.dat||(dat==p.dat&&num>p.num);
}
};
bool cmp(Segment a,Segment b)
{
return a.num<b.num;
}
vector<Segment> vec;
BIT tree;
int main()
{
;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
vec.clear();
; i<=n; ++i)
{
int t;
scanf("%d",&t);
vec.push_back(Segment(i,t));
}
; i<m; ++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
vec.push_back(Segment(-m+i,z,x,y));
}
sort(vec.begin(),vec.end());
tree.clear();
; i<vec.size(); ++i)
{
) tree.add(vec[i].num,);
);
}
sort(vec.begin(),vec.end(),cmp);
printf("Case %d:\n",++kase);
; i<vec.size(); ++i)
) printf("%d\n",vec[i].ans);
else break;
}
;
}
HDU 4417 - Super Mario ( 划分树+二分 / 树状数组+离线处理+离散化)的更多相关文章
- HDU 4417 Super Mario(划分树)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU 4417 Super Mario(划分树问题求不大于k的数有多少)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU 4417 Super Mario(划分树+二分)
题目链接 #include <cstdio> #include <cstring> #include <algorithm> using namespace std ...
- HDU 4417 Super Mario(2012杭州网络赛 H 离线线段树)
突然想到的节约时间的方法,感觉6翻了 给你n个数字,接着m个询问.每次问你一段区间内不大于某个数字(不一定是给你的数字)的个数 直接线段树没法做,因为每次给你的数字不一样,父节点无法统计.但是离线一 ...
- HDU 4417 Super Mario (划分树)(二分)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- hdu 4417 Super Mario/树套树
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题意很简单,给定一个序列求一个区间 [L, R,]中小于等于H的元素的个数. 好像函数式线段树可 ...
- 主席树:HDU 4417 Super Mario
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu 4417 Super Mario 树状数组||主席树
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Prob ...
随机推荐
- Jenkins运行完Test后,把ngreport生成的测试报告 拷贝到相应的文件夹
F:cd F:\program\apache-tomcat-7.0.67\webapps\Set currentPath=F:\program\apache-tomcat-7.0.67\webapps ...
- bzoj题解汇总(1032~1051)
bzoj1034:贪心 bzoj1036:树剖 bzoj1037:一个比较巧妙,利用连续性维护的dp. http://www.cnblogs.com/Sdchr/p/6129496.html bzoj ...
- python中range和xrange的区别
1.range生成一个列表:xrange生成一个生成器 2.用法都差不多
- DOI EXCEL显示报表
我这个是比较不规则的数据填充 1.程序开头,定义一个工作区,存对应单元格的值: BEGIN OF TY_EXCEL, C031() TYPE C, C032() TYPE C, C033() TYPE ...
- Football(POJ3071)
Football Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3469 Accepted: 1782 Descript ...
- 分形树Fractal tree介绍——具体如何结合TokuDB还没有太懂,先记住其和LSM都是一样的适合写密集
在目前的Mysql数据库中,使用最广泛的是innodb存储引擎.innodb确实是个很不错的存储引擎,就连高性能Mysql里都说了,如果不是有什么很特别的要求,innodb就是最好的选择.当然,这偏文 ...
- CSS3学习教程:Media Queries详解
说起CSS3的新特性,就不得不提到 Media Queries . Media Queries 的引入,其作用就是允许添加表达式用以确定媒体的情况,以此来应用不同的样式表.换句话说,其允许我们在不改变 ...
- [Jquery]网页定位导航特效
描述:左右联动的导航,非常适合展示页面内容多,区块划分又很明显的,点击右边固定导航项时,左边的内容跟着切换.滑动滚动条的时候,右边的导航也随着左边的展示而进行高亮切换. 思路:比较滚动距离和楼层距离( ...
- 哈希(Hask)
编辑 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射 ...
- iOS https(SSL/TLS)数据捕获
要捕获iPhone上的appstore的数据还真的没那么容易,以前介绍的那些使用代理手工导入证书的方法已经完全失效了,结果就是安装证书之后再打开appstore也无法正常的建立连接.按照我的分析其实是 ...