HDU 4638 Group 【树状数组,分块乱搞(莫队算法?)】
根据题目意思,很容易得出,一个区间里面连续的段数即为最少的group数。
题解上面给的是用树状数组维护的。
询问一个区间的时候,可以一个一个的向里面添加,只需要判断a[i]-1 和 a[i]+1是否已经添加在内,如果两个都在,则总段数减1,如果两个都不在,总段数加1,其他情况总段数不变了。这里有一个需要深入理解的就是其实无论是按顺序添加还是随便添加,统计结果是不变的,但是要看怎么维护了。
每加入一个点,都会有一个改变量v[i],那么此时总段数就是sum{ v[i] } (1 <= i <= x) ,因此用树状数组维护前缀和即可。
树状数组实现:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 101000
bool vis[N];
int n, s[N], m, ans[N], a[N], p[N];
struct node {
int l, r, id;
bool operator<(const node &x) const {
return r > x.r;
}
} q[N];
inline int lowbit(int x) {
return x&(-x);
}
void add(int x, int v) {
while (x <= n) {
s[x] += v;
x += lowbit(x);
}
}
int sum(int x) {
int ret = 0;
while (x) {
ret += s[x];
x -= lowbit(x);
}
return ret;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i=1; i<=n; i++) {
scanf("%d", &a[i]);
p[a[i]] = i;
}
memset(s, 0, sizeof(s));
memset(vis, false, sizeof(vis));
for (int i=n; i>0; i--) {
if (vis[a[i]-1] && vis[a[i]+1]) add(i, -1);
if (!vis[a[i]-1] && !vis[a[i]+1]) add(i, 1);
vis[a[i]] = true;
} for (int i=0; i<m; i++) {
scanf("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
} sort(q, q+m);
int j = n;
for (int i=0; i<m; i++) {
while (j > q[i].r) {
if (a[j]>1 && p[a[j]-1] < j) add(p[a[j]-1], 1);
if (a[j]<n && p[a[j]+1] < j) add(p[a[j]+1], 1);
j--;
}
ans[q[i].id] = sum(q[i].r) - sum(q[i].l-1);
} for (int i=0; i<m; i++) printf("%d\n", ans[i]);
} return 0;
}
比赛时候,我用的分块的思想,想到复杂度是O(n*sqrt(n))的,可能有点悬,结果TLE了,以为真的是卡时间了,其实是自己的代码写残了(一个小细节害死人啊),调试了很长时间,直接用原题的大数据debug是要命啊。总算找到bug了。其实也是可以过的么……呵呵……数据水?
这种解法和CF 86D Powerful array 的解法是一样的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 100100
bool vis[N];
int a[N], n, m, all, L, R, ans[N]; struct node {
int l, r, b, id;
bool operator<(const node &x)const{
if (b == x.b) return r < x.r;
return b < x.b;
}
} q[N]; void query(int x, int y, int flag) {
if (flag != 0) {
for (int i=x; i<L; i++) {
vis[a[i]] = true;
if (vis[a[i]-1] && vis[a[i]+1]) all--;
else if (!vis[a[i]-1] && !vis[a[i]+1]) all++;
}
for (int i=R+1; i<=y; i++) {
vis[a[i]] = true;
if (vis[a[i]-1] && vis[a[i]+1]) all--;
else if (!vis[a[i]-1] && !vis[a[i]+1]) all++;
}
for (int i=L; i<x; i++) {
vis[a[i]] = false;
if (vis[a[i]-1] && vis[a[i]+1]) all++;
else if (!vis[a[i]-1] && !vis[a[i]+1]) all--;
}
for (int i=y+1; i<=R; i++) {
vis[a[i]] = false;
if (vis[a[i]-1] && vis[a[i]+1]) all++;
else if (!vis[a[i]-1] && !vis[a[i]+1]) all--;
}
} else {
all = 0;
for (int i=x; i<=y; i++) {
vis[a[i]] = true;
if (vis[a[i]-1] && vis[a[i]+1]) all--;
else if (!vis[a[i]-1] && !vis[a[i]+1]) all++;
}
}
L = x, R = y;
}
int main() {
int T;
scanf("%d", &T); while (T--) {
scanf("%d%d", &n, &m);
int block_size = sqrt(n); for (int i=1; i<=n; i++) scanf("%d", &a[i]);
for (int i=0; i<m; i++) {
scanf("%d%d", &q[i].l, &q[i].r);
q[i].b = q[i].l / block_size;
q[i].id = i;
}
sort(q, q+m);
memset(vis, false, sizeof(vis)); for (int i=0; i<m; i++) {
query(q[i].l, q[i].r, i);
ans[q[i].id] = all;
}
for (int i=0; i<m; i++) printf("%d\n", ans[i]);
} return 0;
}
HDU 4638 Group 【树状数组,分块乱搞(莫队算法?)】的更多相关文章
- HDU 4638 Group 树状数组 + 思路
实际上就是问这个区间编号连续的段的个数,假如一个编号连续的段有(a+b)个人,我把他们分在同一组能得到的分值为(a+b)^2,而把他们分成人数为a和b的两组的话,得到的分值就是a^2+b^2,显然(a ...
- HDU 4638 Group ★(树状数组)
题意 询问一段区间里的数能组成多少段连续的数. 思路 先考虑从左往右一个数一个数添加,考虑当前添加了i - 1个数的答案是x,那么可以看出添加完i个数后的答案是根据a[i]-1和a[i]+1是否已经添 ...
- 区间的关系的计数 HDU 4638 离线+树状数组
题目大意:给你n个人,每个人都有一个id,有m个询问,每次询问一个区间[l,r],问该区间内部有多少的id是连续的(单独的也算是一个) 思路:做了那么多离线+树状数组的题目,感觉这种东西就是一个模板了 ...
- 【bzoj4889】[Tjoi2017]不勤劳的图书管理员 树状数组+分块+二分
题目描述(转自洛谷) 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打 ...
- BZOJ_2141_排队_树状数组+分块
BZOJ2141_排队_树状数组+分块 Description 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了 ...
- 【BZOJ2141】排队 树状数组+分块
[BZOJ2141]排队 Description 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备 ...
- BZOJ2141 排队 树状数组 分块
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2141.html 题目传送门 - BZOJ2141 题意 给定一个序列 $a$ ,先输出原先的逆序对数. ...
- 【BZOJ】4129: Haruna’s Breakfast 树分块+带修改莫队算法
[题意]给定n个节点的树,每个节点有一个数字ai,m次操作:修改一个节点的数字,或询问一条树链的数字集合的mex值.n,m<=5*10^4,0<=ai<=10^9. [算法]树分块+ ...
- 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法
[题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...
- hdu4638 group 树状数组
连接:http://acm.hdu.edu.cn/showproblem.php?pid=4638 题意:就给给你n个数(大小在1-n里),然后给你连续的可以构成一个块,再给你N个询问,每个询问一个l ...
随机推荐
- C#线程池ThreadPool.QueueUserWorkItem接收线程执行的方法返回值
最近在项目中需要用到多线程,考虑了一番,选择了ThreadPool,我的需求是要拿到线程执行方法的返回值, 但是ThreadPool.QueueUserWorkItem的回调方法默认是没有返回值的,搜 ...
- oracle批量导入数据
关键代码 OracleDataAdapter da=new OracleDataAdapter(); string sql_select = string.Format("select id ...
- 在C语言中使用scanf语句时遇到的问题总结
在使用visual studio2013编写c语言代码时,遇到了这样的几个小问题,进行如下的总结. 1, 关于使用scanf语句报错的解决方案1 #include <stdio.h> in ...
- 十一、C# 泛型
为了促进代码重用,尤其是算法的重用,C#支持一个名为泛型的特性. 泛型与模块类相似. 泛型使算法和模式只需要实现一交.而不必为每个类型都实现一次.在实例化的时候,传入相应的数据类型便可. 注:可空值类 ...
- WPF 自定义滚动条样式
先看一下效果: 先分析一下滚动条有哪儿几部分组成: 滚动条总共有五部分组成: 两端的箭头按钮,实际类型为RepeatButton Thumb 两端的空白,实际也是RepeatButton 最后就是Th ...
- 深入理解ReentrantLock
在Java中通常实现锁有两种方式,一种是synchronized关键字,另一种是Lock.二者其实并没有什么必然联系,但是各有各的特点,在使用中可以进行取舍的使用.首先我们先对比下两者. 实现: 首先 ...
- hdoj 1087 (DP)
代码: #include<iostream> #include<cmath> using namespace std; int a[1005], dp[1005]; ...
- asp.net 网站和asp.net Web 应用程序的一处不同
环境为:VS2008Team+.net3.5 asp.net 网站前台页面<%= %>这样绑定可以,asp.net Web 应用程序就不可以 示例代码如下: 1.asp.net网站 < ...
- SGU 118.Digital root
时间限制:0.25s 空间限制:4M 题目大意 给出n个数,求n1+n1*n2+n1*n2*n3+n1...nn 的数根,数根是一个数各个位置数字和的树根,个位数的数根为它本身. 例如,f[987]= ...
- CSS实现DIV三角形
本文内容收集来自网络 #triangle-up { width:; height:; border-left: 50px solid transparent; border-right: 50px s ...