Super Mario 树状数组离线 || 线段树
Super Mario
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5560 Accepted Submission(s): 2532
For each test data:
The first line contains two integers n, m (1 <= n <=10^5, 1 <= m <= 10^5), n is the length of the road, m is the number of queries.
Next line contains n integers, the height of each brick, the range is [0, 1000000000].
Next m lines, each line contains three integers L, R,H.( 0 <= L <= R < n 0 <= H <= 1000000000.)
10 10
0 5 2 7 5 4 3 8 7 7
2 8 6
3 5 0
1 3 1
1 9 4
0 1 0
3 5 5
5 5 1
4 6 3
1 5 7
5 7 3
4
0
0
3
1
2
0
1
5
1
http://acm.hdu.edu.cn/showproblem.php?pid=4417
一开始的时候,很难想,和以前的树状数组不同,但是有一点是固定的。
既然要是区间里的个数,那么就肯定离不开L, R
开始的时候还以为学以前的区间统计不同数字的个数一样。对R排序,然后每个压进树状数组。
但是这样不行,查询元素的变得十分麻烦。
比如1、5、7、3
我把这些元素都压进去了,然后查询[3, 4]小于等于6的个数,就会很麻烦。
既要减去[1, 2]的,也有些数字比6大。、
主要是没用上L和R。这两个是必须用的,都是getsum(R) - getsum(L - 1)进而得到答案。都是这个套路。
那么就是看看[L, R]这一段连续的区间,有多少个数是小于等于val的。那么我们先保证,现在每一个压进树状
数组的元素都是<=val的,这个可以保证,然后更新数字的时候,就是跟新他们的位置,所以这时候查询就直接来就行了。
这一招保证每一次query的时候元素都是合法的技巧,以前用过一次,可惜忘记了。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 1e5 + ;
int c[maxn];
int n, m;
int lowbit(int x) {
return x & (-x);
}
void UpDate(int pos, int val) {
while (pos <= n) {
c[pos] += val;
pos += lowbit(pos);
}
}
int getsum(int pos) {
int ans = ;
assert(pos >= );
while (pos) {
ans += c[pos];
pos -= lowbit(pos);
}
return ans;
}
struct haha {
int val, id;
bool operator < (const struct haha & rhs) const {
return val < rhs.val;
}
}a[maxn];
struct node {
int L, R, id, val;
bool operator < (const struct node & rhs) const {
return val < rhs.val;
}
}query[maxn];
int ans[maxn];
void init() {
memset(c, , sizeof c);
}
void work() {
scanf("%d%d", &n, &m);
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i].val);
a[i].id = i;
}
sort(a + , a + + n);
for (int i = ; i <= m; ++i) {
scanf("%d%d%d", &query[i].L, &query[i].R, &query[i].val);
query[i].L++;
query[i].R++;
query[i].id = i;
}
sort(query + , query + + m);
int now = ;
for (int i = ; i <= m; ++i) {
while (now <= n && query[i].val >= a[now].val) {
UpDate(a[now].id, );
now++;
}
ans[query[i].id] = getsum(query[i].R) - getsum(query[i].L - );
}
static int f = ;
printf("Case %d:\n", ++f);
for (int i = ; i <= m; ++i) {
printf("%d\n", ans[i]);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
int t;
scanf("%d", &t);
while (t--) {
init();
work();
}
return ;
}
我这个线段树不是其他线段树。
我的每个节点都保存了所有区间的数字。并且排序
就是把归并排序的过程记录下来了。
然后对于每一个个查询。
1、如果区间全部包含了,那么直接二分查找即可。
2、递归搜索。
注意pushUp的时候,要先vector<>.resize();
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#define root 1, n, 1
#define lson L, mid, cur << 1
#define rson mid + 1, R, cur << 1 | 1
const int maxn = 1e5 + ;
vector<int>seg[maxn << ];
int a[maxn];
int n, m;
void pushUp(int cur) {
// cout << "ff" << endl;
// cout << seg[cur << 1].size() << endl;
merge(seg[cur << ].begin(), seg[cur << ].end(), seg[cur << | ].begin(), seg[cur << | ].end(), seg[cur].begin());
}
void build(int L, int R, int cur) {
if (L == R) {
seg[cur].clear();
seg[cur].push_back(a[L]);
return;
}
int mid = (L + R) >> ;
build(lson);
build(rson);
seg[cur].resize(R - L + );
pushUp(cur);
}
int query(int be, int en, int val, int L, int R, int cur) {
if (L >= be && R <= en) {
if (val >= seg[cur].back()) {
return R - L + ;
} else {
int pos = upper_bound(seg[cur].begin(), seg[cur].end(), val) - seg[cur].begin();
return pos;
}
}
int mid = (L + R) >> ;
int lans = , rans = ;
if (mid >= be) {
lans = query(be, en, val, lson);
}
if (mid < en) {
rans = query(be, en, val, rson);
}
return lans + rans;
}
void upDate(int pos, int val, int L, int R, int cur) {
if (L == R) {
if (pos == L) {
seg[cur].clear();
seg[cur].push_back(val);
}
return;
}
int mid = (L + R) >> ;
if (pos <= mid) upDate(pos, val, lson);
else upDate(pos, val, rson);
pushUp(cur);
}
void work() {
scanf("%d%d", &n, &m);
// cout << n << " " << m << endl;
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
}
build(root);
// for (int i = 0; i < seg[1].size(); ++i) {
// cout << seg[1][i] << " ";
// }
// cout << endl;
// cout << "ff" << endl;
static int f = ;
printf("Case %d:\n", ++f);
while (m--) {
int be, en, x;
scanf("%d%d%d", &be, &en, &x);
be++;
en++;
int res = query(be, en, x, root);
printf("%d\n", res);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
int t;
scanf("%d", &t);
while (t--) work();
return ;
}
Super Mario 树状数组离线 || 线段树的更多相关文章
- [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】
题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1384 Solved: 629[Submit][Stat ...
- [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...
- POJ 1195 Mobile phones (二维树状数组或线段树)
偶然发现这题还没A掉............速速解决了............. 树状数组和线段树比较下,线段树是在是太冗余了,以后能用树状数组还是尽量用......... #include < ...
- 【BZOJ3196】二逼平衡树(树状数组,线段树)
[BZOJ3196]二逼平衡树(树状数组,线段树) 题面 BZOJ题面 题解 如果不存在区间修改操作: 搞一个权值线段树 区间第K大--->直接在线段树上二分 某个数第几大--->查询一下 ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- P3157 [CQOI2011]动态逆序对(树状数组套线段树)
P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...
- HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
Jam's problem again Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- BZOJ 1901 Zju2112 Dynamic Rankings 树状数组套线段树
题意概述:带修改求区间第k大. 分析: 我们知道不带修改的时候直接上主席树就可以了对吧?两个版本号里面的节点一起走在线段树上二分,复杂度是O((N+M)logN). 然而这里可以修改,主席树显然是凉了 ...
随机推荐
- 新手必备的SEO优化工具
- 微软下一代站点开发框架:ASP.NET MVC 6 新特性揭秘
国内第一个<微软下一代站点开发框架:ASP.NET MVC 6 新特性揭秘 >课程 微软特邀讲师 徐雷!周六晚8点YY预定:id=28447" href="htt ...
- PrintWrite
向文本输出流打印对象的格式化表示形式.此类实现在 PrintStream 中的所有 print 方法.它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入. 与 Print ...
- 组合模式(遍历树,file基表示文件也表示文件夹)
组合模式多个对象形成树形结构以表示“整体--部分”的结构层次.组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性. 组合模式又可以称为“合成模式“ 或 ”整体-部分模式”,属于对 ...
- kbmMW实现sql查询(图文并茂)
kbmMW对于Delphi来说,是最好的多层框架,没有之一,无论是效率.稳定及架构都让人无可挑剔,尤其自Delphi支持跨平台开发以来,随着Delphi支持ios及Android移动开发,KbmMW也 ...
- 【扬中集训DAY2T2】 机智的AmyZhi
[题目链接] 点击打开链接 [算法] 据说标算是暴力? 从N-200开始搜 不过我用了搜索+一些奇怪的剪枝,也A了.... [代码] 标程 #include<bits/stdc++.h> ...
- mysql导出 数据库字典
USE information_schema; --切记这里不能忘掉 SELECT T.TABLE_SCHEMA AS '数据库名称', T.TABLE_NAME AS '表名', T.TABLE_T ...
- Bootstrap-CSS:按钮
ylbtech-Bootstrap-CSS:按钮 1.返回顶部 1. Bootstrap 按钮 本章将通过实例讲解如何使用 Bootstrap 按钮.任何带有 class .btn 的元素都会继承圆角 ...
- vue 随笔3
在整个vue项目中index.js只能有一个 ,创建vue组件实例的代码只能写在main.js中或者index.js中,别的文件中都是使用export default 常量 或者是方法
- BZOJ1787 meet
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1787 水题,但是结论很有趣. 题目求的是距离三个点之和最小的点. 这个很显然是在三个LCA上, ...