您的位置:首页 > 其它

hdu4638 Group(树状数组)

2015-08-27 14:16 197 查看
题目大意:

给一个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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: