HDU 4638 Group(莫队算法)





http://acm.hdu.edu.cn/showproblem.php?pid=4638






题目大意:

N 个数字   m次询问   每次询问一个区间    问区间内连续的数字有多少组





分析:

莫队算法就可以    

设置一个flag数组   


add时将 flag[a[index]]  设置为 1    表示加入元素a[index]    

如果元素a[index]   两侧的值都没有在之前组内   则a[index]自成一组  ans++ 

如果元素a[index]   两侧的值都在之前组内   则a[index]起桥梁作用链接两组  ans--

其他情况可分到任意一组   ans不变


add时将 flag[a[index]]  设置为 0    表示删除元素a[index]    

如果元素a[index]   两侧的值都没有在之前组内   则a[index]自成一组  删掉后  ans--

如果元素a[index]   两侧的值都在之前组内   则a[index]起桥梁作用链接两组  删掉后   桥梁断裂   ans++

其他情况是删除组中元素    ans不变






AC代码:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include<list>
#include <bitset>
#include <climits>
#include <algorithm>
#define gcd(a,b) __gcd(a,b)
#define mset(a,n) memset(a,n,sizeof(a))
#define FIN	freopen("input.txt","r",stdin)
#define FOUT 	freopen("output.txt","w",stdout)
typedef long long LL;
const LL mod=1e9+7;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
using namespace std;
int a[100005];
int pos[100005];
int flag[100005];
int ans;
int maxa,maxd,mina,mind;
struct node{
    int l,r;
    int index;
    int ans;
}Q[100005];
bool cmp1(node x,node y){
    return pos[x.l]==pos[y.l]?x.r<y.r:x.l<y.l;
}
bool cmp2(node x,node y){
    return x.index<y.index;
}
void add(int index){
    flag[a[index]]=1;
    if (!(flag[a[index]+1]||flag[a[index]-1])) ans++;
    else if (flag[a[index]+1]&&flag[a[index]-1]) ans--;
}
void del(int index){
    flag[a[index]]=0;
    if (!(flag[a[index]+1]||flag[a[index]-1])) ans--;
    else if (flag[a[index]+1]&&flag[a[index]-1]) ans++;
}
int main (){
    int t;
    scanf ("%d",&t);
    while (t--){
        int n,m;
        scanf ("%d%d",&n,&m);
        mset(a,0);mset(Q,0);mset(flag,0);
        int div=sqrt(n);
        for (int i=1;i<=n;i++) scanf ("%d",&a[i]);
        for (int i=1;i<=m;i++) scanf ("%d%d",&Q[i].l,&Q[i].r),Q[i].index=i,pos[i]=(i-1)/div+1;
        sort(Q+1,Q+m+1,cmp1);
        int ll=1,rr=0;
        ans=0;
        for (int i=1;i<=m;i++){
            while (rr<Q[i].r) rr++,add(rr);
            while (rr>Q[i].r) del(rr),rr--;
            while (ll<Q[i].l) del(ll),ll++;
            while (ll>Q[i].l) ll--,add(ll);
            Q[i].ans=ans;
        }
        sort(Q+1,Q+m+1,cmp2);
        for (int i=1;i<=m;i++) printf ("%d\n",Q[i].ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值