Group(莫队离线)
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3453 Accepted Submission(s): 1700
Problem Description
There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interval of men to make some group. K men in a group can create K*K value. The value of an interval is sum of these value of groups.* The people of same group’s id must be continuous.* Now we chose an interval of men and want to know there should be how many groups so the value of interval is max.
Input
First line is T indicate the case number.
For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query.
Then a line have n number indicate the ID of men from left to right.
Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].
Output
For every query output a number indicate there should be how many group so that the sum of value is max.
Sample Input
1
5 2
3 1 2 5 4
1 5
2 4
Sample Output
1
2
题意
给出n个数,代表每个人的id,连续的id就表示他们互相是朋友,接下来是m次询问,对于每一次查询区间,输出有多少组朋友。
解题思路
由于没有更新操作,可以直接用莫队算法离线处理。具体见代码。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+50;
int arr[maxn],pos[maxn];
struct node
{
int l,r,id;
} p[maxn];
int l,r,ans,res[maxn],flag[maxn];
int 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 x)
{
if(!flag[arr[x]-1]&&!flag[arr[x]+1]) ans++;
if(flag[arr[x]-1]&&flag[arr[x]+1]) ans--;
flag[arr[x]]=1;
}
void sub(int x)
{
if(flag[arr[x]-1]&&flag[arr[x]+1]) ans++;
if(!flag[arr[x]-1]&&!flag[arr[x]+1]) ans--;
flag[arr[x]]=0;
}
int main()
{
#ifdef DEBUG
freopen("in.txt","r",stdin);
#endif // DEBUG
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
memset(flag,0,sizeof(int)*(n+1));
int block=(int)sqrt(1.0*n);
for(int i=1; i<=n; i++)
scanf("%d",&arr[i]);
for(int i=1; i<=m; i++)
scanf("%d%d",&p[i].l,&p[i].r),pos[i]=i/block,p[i].id=i;
sort(p+1,p+1+m,cmp);
l=1,r=0,ans=0;
for(int i=1; i<=m; i++)
{
if(p[i].l>r||p[i].r<l)
{
while(l<=r) flag[arr[l++]]=0;//重置这个不相关的区间
ans=0;//重置结果
for(int j=p[i].l; j<=p[i].r; j++)
{
flag[arr[j]]=1;
if(flag[arr[j]-1]&&flag[arr[j]+1]) ans--;
if(!flag[arr[j]-1]&&!flag[arr[j]+1]) ans++;
}
l=p[i].l,r=p[i].r;//更新区间
res[p[i].id]=ans;
continue;
}
while(l<p[i].l) sub(l++);
while(l>p[i].l) add(--l);
while(r<p[i].r) add(++r);
while(r>p[i].r) sub(r--);
res[p[i].id]=ans;
}
for(int i=1; i<=m; i++) printf("%d\n",res[i]);
}
return 0;
}