根据题目意思,很容易得出,一个区间里面连续的段数即为最少的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 【树状数组,分块乱搞(莫队算法?)】的更多相关文章

  1. HDU 4638 Group 树状数组 + 思路

    实际上就是问这个区间编号连续的段的个数,假如一个编号连续的段有(a+b)个人,我把他们分在同一组能得到的分值为(a+b)^2,而把他们分成人数为a和b的两组的话,得到的分值就是a^2+b^2,显然(a ...

  2. HDU 4638 Group ★(树状数组)

    题意 询问一段区间里的数能组成多少段连续的数. 思路 先考虑从左往右一个数一个数添加,考虑当前添加了i - 1个数的答案是x,那么可以看出添加完i个数后的答案是根据a[i]-1和a[i]+1是否已经添 ...

  3. 区间的关系的计数 HDU 4638 离线+树状数组

    题目大意:给你n个人,每个人都有一个id,有m个询问,每次询问一个区间[l,r],问该区间内部有多少的id是连续的(单独的也算是一个) 思路:做了那么多离线+树状数组的题目,感觉这种东西就是一个模板了 ...

  4. 【bzoj4889】[Tjoi2017]不勤劳的图书管理员 树状数组+分块+二分

    题目描述(转自洛谷) 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打 ...

  5. BZOJ_2141_排队_树状数组+分块

    BZOJ2141_排队_树状数组+分块 Description 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了 ...

  6. 【BZOJ2141】排队 树状数组+分块

    [BZOJ2141]排队 Description 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备 ...

  7. BZOJ2141 排队 树状数组 分块

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2141.html 题目传送门 - BZOJ2141 题意 给定一个序列 $a$ ,先输出原先的逆序对数. ...

  8. 【BZOJ】4129: Haruna’s Breakfast 树分块+带修改莫队算法

    [题意]给定n个节点的树,每个节点有一个数字ai,m次操作:修改一个节点的数字,或询问一条树链的数字集合的mex值.n,m<=5*10^4,0<=ai<=10^9. [算法]树分块+ ...

  9. 【BZOJ】3052: [wc2013]糖果公园 树分块+带修改莫队算法

    [题目]#58. [WC2013]糖果公园 [题意]给定n个点的树,m种糖果,每个点有糖果ci.给定n个数wi和m个数vi,第i颗糖果第j次品尝的价值是v(i)*w(j).q次询问一条链上每个点价值的 ...

  10. hdu4638 group 树状数组

    连接:http://acm.hdu.edu.cn/showproblem.php?pid=4638 题意:就给给你n个数(大小在1-n里),然后给你连续的可以构成一个块,再给你N个询问,每个询问一个l ...

随机推荐

  1. OpenCart 之registry功用

    1. “Registry”设计模式 在OpenCart中,Registry是整个系统的信息中枢. Registry是一个单例(Singleton),在index.php起始页面中, 首先作为构造函数参 ...

  2. pthread_rwlock_t读写锁函数说明

    读写锁 索引: 初始化一个读写锁pthread_rwlock_init 读锁定读写锁      pthread_rwlock_rdlock 非阻塞读锁定 pthread_rwlock_tryrdloc ...

  3. mysql如何将一个表导出为excel表格

    方法一:进入到mysql的控制台,输入: 1. SELECT * INTO OUTFILE ‘./test.xls‘ FROM tb1 WHERE 1 ORDER BY id DESC  LIMIT ...

  4. getJSON回调函数不执行问题?

    利用getJSON异步请求时,回调函数不执行,不知道是什么问题? php 返回数据 header("Content-type:text/json"); echo json_enco ...

  5. Linux 使用yum install安装mysql登陆不上解决办法

    CentOS yum安装mysql后 Can’t connect to local MySQL server through socket ‘/var/lib/ CentOS Can’t connec ...

  6. bzoj3047: Freda的传呼机 && 2125: 最短路

    Description 为了随时与rainbow快速交流,Freda制造了两部传呼机.Freda和rainbow所在的地方有N座房屋.M条双向光缆.每条光缆连接两座房屋,传呼机发出的信号只能沿着光缆传 ...

  7. ios+oc面试题

    ios+oc面试题     浅复制和深复制的区别?//浅拷贝和深拷贝答案:浅层复制(copy):只复制指向对象的指针,而不复制引用对象本身.//通过对象的指针来访问这个对象深层复制(mutableCo ...

  8. WPF学习笔记-使用自定义资源字典(style)文件

    1.添加资源字典文件style.xmal 2.在资源字典中添加自定义style等 <ResourceDictionary xmlns="http://schemas.microsoft ...

  9. JQuery 判断IPad、IPhone、Android是横屏还是竖屏(Window.Orientation实现)

    在ipad.iphone网页开发中,我们很可能需要判断是横屏或者竖屏.下面就来介绍如何用 jQuery 判断iPad.iPhone.Android是横屏还是竖屏的方法. 代码如下: function ...

  10. ROR入门之旅

    mac上为了不在登录画面看到其他账户,我禁用了root账户,而每次用Terminal的时候,先获得sudo账户的权限: sudo -s mac本身就安装有ruby ruby -v 查看当前安装的rub ...