HDU 4638 Group(莫队离线)

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;
}

猜你喜欢

转载自blog.csdn.net/qq_36258516/article/details/81367880