HDU 4638 Groub 线段树离线,莫队,分块法

来源:互联网 发布:阿里云短信接口 php 编辑:程序博客网 时间:2024/05/22 03:40

题意:找到区间里有多少组连续数字串。
PS:由于网上关于这个题的解法非常多,不懂自己去看,我自己写了3种解法,主要比较效率。
解法1: 询问离线,右端点排序,树状数组(线段树维护)
//7876kb, 795ms, 1331kb

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6+7;int T, n, m, a[maxn], p[maxn], ans[maxn];struct node{    int l, r, id;    node(){}    node(int l, int r, int id) : l(l), r(r), id(id){}    bool operator < (const node &rhs) const{        return r < rhs.r;    }}q[maxn];namespace BIT{    int c[maxn];    void init(){memset(c, 0, sizeof(c));}    inline int lowbit(int x){return x&-x;}    inline void add(int i, int v){for(; i<= n; i += lowbit(i)) c[i] += v;}    inline query(int i){int res = 0; for(; i; i -= lowbit(i)) res += c[i]; return res;}}using namespace BIT;int main(){    scanf("%d", &T); while(T--){        scanf("%d%d", &n, &m);        for(int i = 1; i <= n; i++){            scanf("%d", &a[i]); p[a[i]] = i;        }        for(int i = 1; i <= m; i++){scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i;}        sort(q + 1, q + m + 1);        init();        int j = 1;        for(int i = 1; i <= n; i++){            add(i, 1);            if(a[i] > 1 && p[a[i] - 1] < i) add(p[a[i] - 1], -1);            if(a[i] < n && p[a[i] + 1] < i) add(p[a[i] + 1], -1);            while(j <= m && q[j].r == i){                ans[q[j].id] = query(q[j].r) - query(q[j].l - 1); j++;            }        }        for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);    }    return 0;}

解法2:莫队 O(n^1.5)
//4944 kb, 1060ms, 1287b

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6+7;int T, n, m, a[maxn], pos[maxn], Ans[maxn], ans;struct node{    int l, r, id;    node(){}    node(int l, int r, int id) : l(l), r(r), id(id){}}q[maxn];bool vis[maxn];bool cmp(node a, node b){    if(pos[a.l] == pos[b.l]) return a.r < b.r;    return pos[a.l] < pos[b.l];}void update(int x, int d){    vis[x] = d;    if(d) ans += 1 - vis[x + 1] - vis[x - 1];    else ans += vis[x + 1] + vis[x - 1] - 1;}int main(){    scanf("%d", &T); while(T--){        scanf("%d%d", &n, &m);        memset(vis, 0, sizeof(vis));        int block = sqrt(n);        for(int i = 1; i <= n; i++){            scanf("%d", &a[i]); pos[i] = (i - 1) / block;        }        for(int i = 1; i <= m; i++){scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i;}        sort(q + 1, q + m + 1, cmp);        int L = 1, R = 0; ans = 0;        for(int i = 1; i <= m; i++){            int id = q[i].id;            while(R < q[i].r) R++, update(a[R], 1);            while(R > q[i].r) update(a[R], 0), R--;            while(L < q[i].l) update(a[L], 0), L++;            while(L > q[i].l) L--, update(a[L], 1);            Ans[id] = ans;        }        for(int i = 1; i <= m; i++) printf("%d\n", Ans[i]);    }    return 0;}

解法3:分块 (话说这个分块真的不是莫队???毛啊,这就是瞎暴力吧???) O(n^1.5)
//951ms 920kb 2085b

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6+7;int T, n, m, L, R, a[maxn], Ans[maxn], ans;bool vis[maxn];struct node{    int l, r, id, belong;    node(){}    node(int l, int r, int id, int belong) : l(l), r(r), id(id), belong(belong) {}    bool operator < (const node &rhs) const{        if(belong == rhs.belong) return r < rhs.r;        return belong < rhs.belong;    }}q[maxn];void query(int x, int y, int type){    if(type == 1){        ans = 0;        for(int i = x; i <= y; i++){            vis[a[i]] = 1;            if(vis[a[i] - 1] && vis[a[i] + 1]) ans--;            else if(!vis[a[i] - 1] && !vis[a[i] + 1]) ans++;        }    }    else{        for(int i = x; i < L; i++){            vis[a[i]] = 1;            if(vis[a[i] - 1] && vis[a[i] + 1]) ans--;            else if(!vis[a[i] - 1] && !vis[a[i] + 1]) ans++;        }        for(int i = R + 1; i <= y; i++){            vis[a[i]] = 1;            if(vis[a[i] - 1] && vis[a[i] + 1]) ans--;            else if(!vis[a[i] - 1] && !vis[a[i] + 1]) ans++;        }        for(int i = L; i < x; i++){            vis[a[i]] = 0;            if(vis[a[i] - 1] && vis[a[i] + 1]) ans++;            else if(!vis[a[i] - 1] && !vis[a[i] + 1]) ans--;        }        for(int i = y + 1; i <= R; i++){            vis[a[i]] = 0;            if(vis[a[i] - 1] && vis[a[i] + 1]) ans++;            else if(!vis[a[i] - 1] && !vis[a[i] + 1]) ans--;        }    }    L = x, R = y;}int main(){    scanf("%d", &T); while(T--){        scanf("%d%d", &n, &m);        int block = 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].belong = q[i].l / block; q[i].id = i;        }        sort(q + 1, q + m + 1);        memset(vis, 0, sizeof(vis));        ans = 0;        for(int i = 1; i <= m; i++){            query(q[i].l, q[i].r, i);            Ans[q[i].id] = ans;        }        for(int i = 1; i <= m; i++){            printf("%d\n", Ans[i]);        }    }    return 0;}
0 0