HDU - 4638 Group【莫队】

Group

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3080    Accepted Submission(s): 1540


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
 

Source
 

Recommend
zhuyuanchen520
 

思路:

莫队算法。可以用vis数组标记一个值是否出现过,很容易构造add和move函数。add时如果两边值为出现过,可以合并,ans--。。。很不容易想到的是如果本次询问的左右边界在上一次询问的一边,那么移动时就会出现消除一个并不存在的值的情况,同样会出现添加一个已经添加过的值的情况。这种情况需要特殊判断一下。可以将之前的记录全部消除,L定位到q[i].l,R定位到q[i].l-1,然后add(a[++R])即可。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define MAXN 100005
int n,m,block,a[MAXN];
int vis[MAXN],ans,s[MAXN];
struct query
{
    int l,r,id;
}q[MAXN];
bool cmp(query x,query y)
{
    if(x.l/block!=y.l/block)
        return x.l<y.l;
    return x.r<y.r;
}
void add(int x)
{
    vis[x]=1;
    if(vis[x-1] && vis[x+1]) ans--;
    if(!vis[x-1] && !vis[x+1]) ans++;
}
void move(int x)
{
    vis[x]=0;
    if(vis[x-1] && vis[x+1]) ans++;
    if(!vis[x-1] && !vis[x+1]) ans--;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        memset(vis,0,sizeof vis);
        block=sqrt(n*1.0);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id=i;
        }
        sort(q,q+m,cmp);
        ans=1;
        int L=1,R=1;
        vis[a[1]]=1;
        for(int i=0;i<m;i++)
        {
            if(q[i].r<L || q[i].l>R)
            {
                ans=0;
                while(L<=R) vis[a[L++]]=0;//消除之前记录
                L=q[i].l;//将L和R重新定位
                R=q[i].l-1;
                while(R<q[i].r) add(a[++R]);//add操作右移R
                s[q[i].id]=ans;
                continue;
            }
            while(L<q[i].l) move(a[L++]);
            while(L>q[i].l) add(a[--L]);
            while(R<q[i].r) add(a[++R]);
            while(R>q[i].r) move(a[R--]);
            s[q[i].id]=ans;
        }
        for(int i=0;i<m;i++)
            printf("%d\n",s[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013852115/article/details/80137737