题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638
题目大意:给你1-N的任意全排列,询问Q次,每次询问区间[l-r]内的组数,组数的定义为:在一个连续区间中,可以把区间中的数任意分成几组,每组的所有数必须连续,比如
7 5 8的组数为2,即7,8和5。
解题思路:先假设每个数都是一组,然后查找和他相邻的两个数是否在此之前出现过,如果出现则 出现的位置标记减1,最后就是区间求和问题。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 100005
#define lowbit(x) (x&(-x))
int T,n,m;
int s[M],pos[M],a[M],ans[M];
struct node
{
int l,r,id;
}p[M];
bool cmp(node a,node b) {return a.r<b.r;}
void init()
{
for(int i=0;i<=n;i++)
{
s[i]=0;
pos[i]=0;
a[i]=0;
}
}
void insert(int x,int v)
{
while(x<=n)
{
s[x]+=v;
x+=lowbit(x);
}
}
int get_sum(int x)
{
int sum=0;
while(x>0)
{
sum+=s[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[a[i]]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&p[i].l,&p[i].r);
p[i].id=i;
}
sort(p+1,p+1+m,cmp);
memset(s,0,sizeof(s));
int j=1;
for(int i=1;i<=n;i++)
{
insert(i,1);
if(a[i]>1&&pos[a[i]-1]<i)
insert(pos[a[i]-1],-1);
if(a[i]<n&&pos[a[i]+1]<i)
insert(pos[a[i]+1],-1);
while(j<=m&&p[j].r==i)
{
ans[p[j].id]=get_sum(p[j].r)-get_sum(p[j].l-1);
j++;
}
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
return 0;
}