HDU 4638 Group

Group

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


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
2013 Multi-University Training Contest 4

题意为询问一段区间里的数能组成多少段连续的数。先考虑从左往右一个数一个数添加,考虑当前添加了i - 1个数的答案是x,那么添加完i个数后的答案是多少?可以看出,是根据a[i]-1a[i]+1是否已经添加而定的,如果a[i]-1或者a[i]+1已经添加一个,则段数不变,如果都没添加则段数加1,如果都添加了则段数减1。设v[i]为加入第i个数后的改变量,那么加到第x数时的段数就是sum{v[i]} (1<=i<=x}。仔细想想,若删除某个数,那么这个数两端的数的改变量也会跟着改变,这样一段区间的数构成的段数就还是他们的v值的和。将询问离线处理,按左端点排序后扫描一遍,左边删除,右边插入,查询就是求区间和。


#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define prt(k) cout<<#k"="<<k<<endl;
#include<algorithm>
#define N 200033
int c[N],a[N];
int pos[N];
int ans[N];
struct node
{
    int id,l,r;
};
bool cmp(node a,node b)
{
    return a.r>b.r;
}
int lowbit(int x) { return x&-x; }
void update(int x,int v)
{
    while(x<N)
    {
        c[x]+=v;
        x+=lowbit(x);
    }
}
int query(int x)
{
    int r=0;
    while(x>0)
    {
        r+=c[x];
        x-=lowbit(x);
    }
    return r;
}
node q[N];
int n,m;
bool vis[N];
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",a+i),pos[a[i]]=i;
        memset(vis,0,sizeof vis);
        memset(c,0,sizeof c);
        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);
        for(int i=n;i>=1;i--)
        {
            int d=0;    //vis[a[i]-1]+vis[a[i]+1];
            if(vis[a[i]-1]) d++;
            if(vis[a[i]+1]) d++;
            if(d==0)
                update(i,1);
            if(d==2)
                update(i,-1);
            vis[a[i]]=1;
        }
        int j=n;
        for(int i=0;i<m;i++)
        {
            for(;j>q[i].r;j--)
            {
                if(a[j]>1&&pos[a[j]-1]<j)
                {
                    update(pos[a[j]-1],1);
                }
                if(a[j]<n&&pos[a[j]+1]<j)
                {
                    update(pos[a[j]+1],1);
                }
            }
            ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
        }
        for(int i=0;i<m;i++) printf("%d\n",ans[i]);
    }
}


你可能感兴趣的:(算法)