HDU 4638 Group(分组)

时间:2023-03-09 15:22:42
HDU 4638 Group(分组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638

题意:给出一个数列,若干询问。每次询问区间[L,R]的最少有多少段?每一段是连续的一段且这段内的数字也是连续的。

思路:对于新加入一个数字x,若之前x-1和x+1都已经加入了,那么总段数减1,若都没有加入,则总段数加1,若只加入一个,则总段数不变。然后,我们将数列分成 sqrt(n)段,将询问按照左端点放到相应的段中。同一段中按照右端点升序排序。那么在同一段中,右侧最多移动长度n左侧最左移动sqrt(n)。

struct node
{
    int L,R,id;
    
    void get()
    {
        RD(L,R);
        L--; R--;
    }
    
    int operator<(const node &a) const
    {
        return R<a.R;
    }
};

node a[N];
int n,m,d[N],ans[N],h[N];

vector<node> V[505];

int main()
{
    rush()
    {
        RD(n,m);
        int i,len=sqrt(n+1.0),cnt=(n+len-1)/len;
        FOR0(i,cnt) V[i].clear();
        FOR0(i,n) RD(d[i]);
        FOR1(i,m) 
        {
            a[i].get(),a[i].id=i;
            V[a[i].L/len].pb(a[i]);
        }
        FOR0(i,cnt) sort(V[i].begin(),V[i].end());
        
        int x,j,k=1,t,l,r;
        FOR0(i,cnt)
        {
            l=i*len; r=l-1; x=0; clr(h,0);
            FOR0(j,SZ(V[i]))
            {
                while(r<V[i][j].R)
                {
                    t=d[++r];
                    if(h[t-1]&&h[t+1]) x--;
                    else if(!h[t-1]&&!h[t+1]) x++;
                    h[t]=1;
                }
                while(l>V[i][j].L) 
                {
                    t=d[--l];
                    if(h[t-1]&&h[t+1]) x--;
                    else if(!h[t-1]&&!h[t+1]) x++;
                    h[t]=1;
                }
                while(l<V[i][j].L)
                {
                    t=d[l++];
                    if(h[t-1]&&h[t+1]) x++;
                    else if(!h[t-1]&&!h[t+1]) x--;
                    h[t]=0;
                }

ans[V[i][j].id]=x;
            }
        }
        FOR1(i,m) PR(ans[i]);
    }
}