题意:
给
n
个人的编号,每个人都对应一个编号,规定i和i-1,i+1一个群集合
,然后q
个询问询问区间[l,r]
有几个集合
题解:
用 vis[ ] 标记当前区间是要删除还是加入,如果当前区间要加入
x
,就判断当前区间存在vis[i+1]和vis[i-1]
不存在,如果存在res--
,如果不存在,肯定加入的是一个集合,如果只存在其中的一个,肯定不用加减,减的操作也一样,把当前的vis[i]
赋值为0即可,然后判断vis[i+1]和vis[i-1]
存在不存在,如果存在,res++
,原本是一个集合,现在把其他变成了两个集合,反则res--
强调:
缩小和扩大区间的顺序需要注意,那不然会
wa
,一定要先add(++r)然后sub(r--)然后sub(l++)然后add(--l)
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int pos[maxn],ans[maxn],a[maxn];
int vis[maxn];
int res;
struct node
{
int l,r,k;
} q[maxn];
bool cmp(node a,node b)
{
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return pos[a.l]<pos[b.l];
}
void add(int i)
{
vis[a[i]]=1;
if(vis[a[i]-1]&&vis[a[i]+1])
res--;
else if(!vis[a[i]-1]&&(!vis[a[i]+1]))
res++;
//cout<<res<<endl;
}
void sub(int i)
{
vis[a[i]]=0;
if(vis[a[i]-1]&&vis[a[i]+1])
res++;
else if(!vis[a[i]-1]&&(!vis[a[i]+1]))
res--;
//cout<<res<<endl;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
memset(vis,0,sizeof(vis));
res=0;
scanf("%d %d",&n,&m);
int dis=sqrt(n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
pos[i]=i/dis;
}
for(int i=0; i<m; i++)
{
scanf("%d %d",&q[i].l,&q[i].r);
q[i].k=i;
}
sort(q,q+m,cmp);
int l=1,r=0;
for(int i=0; i<m; i++)
{
while(r<q[i].r)
{
add(++r);
}
while(r>q[i].r)
{
sub(r--);
}
while(l<q[i].l)
{
sub(l++);
}
while(l>q[i].l)
{
add(--l);
}
ans[q[i].k]=res;
}
for(int i=0; i<m; i++)
printf("%d\n",ans[i]);
}
}