HDU 4638 Group(莫队算法)

版权声明:没人会转的( ̄▽ ̄) https://blog.csdn.net/j2_o2/article/details/86573684
题目链接
题意

给定一个序列,离线查询多组区间,区间内可任意排列,求最少分成几个连续的序列。

思路

刚开始以为不能任意排列,感觉是RMQ怼了一下发现样例过不了。如果是不能任意排列的串,能不能用RMQ怼,哪位大佬能抬一手ORZ。

算法教程网上多如牛毛这里不再提,开个mp数组,O(1)维护一下相邻区间的转移方法,具体方法参考代码ins,mov函数部分。
此博客主要记录模板自己参考

代码
#include<bits/stdc++.h>
using namespace std;

struct Node
{
    int l, r, id;
}e[100005];
int blo, v[100005], tmp, ans[100005], mp[100005];

bool cmp(Node a, Node b)
{
    if(a.l/blo == b.l/blo) return a.r < b.r;
    return a.l < b.l;
}

void ins(int x)
{
    if(mp[x+1] == 0 && mp[x-1] == 0) ++tmp;
    if(mp[x+1] && mp[x-1]) --tmp;
    mp[x] = 1;
}

void mov(int x)
{
    if(mp[x+1] == 0 && mp[x-1] == 0) --tmp;
    if(mp[x+1] && mp[x-1]) ++tmp;
    mp[x] = 0;
}

int main()
{
    int t;
    for(scanf("%d",&t); t; --t)
    {
        int n, m;
        scanf("%d%d",&n,&m);
        blo = sqrt(n);
        for(int i = 1; i <= n; ++i) scanf("%d",&v[i]);
        for(int i = 0; i < m; ++i)
        {
            e[i].id = i;
            scanf("%d%d",&e[i].l,&e[i].r);
        }
        sort(e,e+m,cmp);
        int l = 1, r = 0;
        tmp = 0;
        memset(mp,0,sizeof(mp));
        for(int i = 0; i < m; ++i)
        {
            while(r < e[i].r) ins(v[++r]);
            while(r > e[i].r) mov(v[r--]);
            while(l < e[i].l) mov(v[l++]);
            while(l > e[i].l) ins(v[--l]);
            ans[e[i].id] = tmp;
        }
        for(int i = 0; i < m; ++i) printf("%d\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/j2_o2/article/details/86573684