hdu4638 Group(树状数组)

来源:互联网 发布:java下载和安装 编辑:程序博客网 时间:2024/05/22 00:42

题目大意:

给一个1-n的排列,然后询问[x,y]区间中有多少个连续的段。

如给一个3 1 2 5 4, 查询是2 4,那么就是问1 2 5中有多少个连续的串,一共有两个串,1、2为一个串,5为一个串

若查询是2 5,则问的是1 2 5 4中有多少个连续的串,一共有两个串, 1、2为一个串, 4、5 为一个串。

 

反思:这一题我想了蛮久的,因为我一直想要去维护每一个串的首个数字,但想了很久都没有想到维护的方法。

后面看了题解后才发现,不仅仅可以通过数串数得到答案,还可以通过一段区间中有多少个相邻的数字对,来得到答案。

若查询区间中有k个相邻数字对,区间长度是m,那么这次的答案就是m - k。

这个其实蛮好理解的,大家举几个例子仔细想一下就明白了。

像1 2 5 4,其中1和2、4和5是相邻的数字对,所以答案就是 4 - 2 = 2

 

现在问题就变成了求一段区间当中有多少个相邻的数字对。

我的解决方法是进行离线查询,对m个询问按照x的大小,从大到小排序,然后根据查询,依次更新区间[n, n], [n-1, n]. [n-2, n] , [n-3, n], [n-4, n] ........ [2, n], [1, n]的数字对的情况:

具体更新方法:从[i+1, n]更新到[i, n],若pos[a[i]+1] > i , 则updata(pos[a[i]+1], 1)。若pos[a[i]-1] > i ,则updata(pos[a[i-1]]. 1)。否则不进行操作。

具体更新代码

void updata(int val, int posx){if (val != n)if (pos[val+1] > posx)updata_tree(pos[val+1], 1);if (val != 1)if (pos[val-1] > posx)updata_tree(pos[val-1], 1);return ;}


 

j = n + 1;for (i=m; i>=1; i--){while (j > q[i].x){j --;updata(a[j], j);}ans[q[i].id] = (q[i].y - q[i].x + 1) - query(q[i].x, q[i].y);}


 

在这个更新基础上,查询就只要直接用树状数组查询区间合就好了。

 

最后附上全部代码:

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <algorithm>using namespace std;const int MAXN = 1e5 + 100;class query{public:int id, x, y;};bool operator < (const query &a, const query &b){return a.x < b.x;}query q[MAXN];int a[MAXN], pos[MAXN], ans[MAXN], h[MAXN];int n, m;int lowbit(int x){return x&(-x);}void updata_tree(int x, int val){while (x <= n){h[x] += val;x += lowbit(x);}return;}int query_tree(int x){int ans = 0;if (x == 0)return 0;while (x > 0){ans += h[x];x -= lowbit(x);}return ans;}void updata(int val, int posx){if (val != n)if (pos[val+1] > posx)updata_tree(pos[val+1], 1);if (val != 1)if (pos[val-1] > posx)updata_tree(pos[val-1], 1);return ;}int query(int x, int y){int ans;ans = query_tree(y) - query_tree(x-1);return ans;}int main(){int T, i, j;scanf("%d",&T);while (T--){scanf("%d%d",&n,&m);for (i=1; i<=n; i++){scanf("%d", &a[i]);pos[a[i]] = i;h[i] = 0;}for (i=1; i<=m; i++){scanf("%d%d",&q[i].x, &q[i].y);q[i].id = i;}sort(q+1, q+m+1);j = n + 1;for (i=m; i>=1; i--){while (j > q[i].x){j --;updata(a[j], j);}ans[q[i].id] = (q[i].y - q[i].x + 1) - query(q[i].x, q[i].y);}for (i=1; i<=m; i++)printf("%d\n", ans[i]);}return 0;}


 

0 0
原创粉丝点击