zoukankan      html  css  js  c++  java
  • 莫队算法小结

    神奇的莫队算法!!!我只能说Qrz,之前一直在一道题上面傻逼了,wa到死,附上链接:http://www.spoj.com/problems/ZQUERY/en/ 个人觉得还是一道蛮不错的题。

    莫队简单粗暴,据说可以再o(nlogn)内解决一切无修改的区间查询问题!!!核心应该就是:1:按左端点分块排序。2:能在o(1)的复杂度内解决[L,R] -> [L,R+1],[L,R]->[L,R-1],[L,R] -> [L-1,R],[L,R] -> [L+1,R]所维护的值,当着o(1)视情况而定。只要保证复杂度满足题目条件即可。

    莫队另外一个优点就是易于实现!!!好写!!!再次Orz莫涛大神!!!

    下面介绍几道入门题:

    1:小Z的袜子:http://www.lydsy.com/JudgeOnline/problem.php?id=2038

    最基本的题,直接给代码了:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define ll long long
    #define N 50010
    
    using namespace std;
    
    const int M = (int)sqrt(1.0*N)+1;
    int n,m;
    int cnt[N],col[N];
    
    struct Command{
        ll l,r,id;
        bool operator < (const Command& rhs) const{
            if(l/M == rhs.l/M)  return r < rhs.r;
            return (l/M) < (rhs.l/M);
        }
    }cmd[N];
    
    struct Ans{
        ll mol,den;
    }ans[N];
    
    ll gcd(ll a,ll b){
        return b == 0 ? a : gcd(b,a%b);
    }
    
    void solve(){
        ll L = 1,R = 0;
        ll temp = 0;
        FOR(i,0,m){
            while(R < cmd[i].r) {
                R ++;
                temp -= cnt[col[R]]*cnt[col[R]];
                cnt[col[R]] ++;
                temp += cnt[col[R]]*cnt[col[R]];
            }
            while(R > cmd[i].r){
                temp -= cnt[col[R]]*cnt[col[R]];
                cnt[col[R]] --;
                temp += cnt[col[R]]*cnt[col[R]];
                R --;
            }
            while(L < cmd[i].l){
                temp -= cnt[col[L]]*cnt[col[L]];
                cnt[col[L]] --;
                temp += cnt[col[L]]*cnt[col[L]];
                L ++;
            }
            while(L > cmd[i].l){
                L --;
                temp -= cnt[col[L]]*cnt[col[L]];
                cnt[col[L]] ++;
                temp += cnt[col[L]]*cnt[col[L]];
            }
            ll x = temp - (R-L+1);
            ll y = (R-L+1)*(R-L);
            if(!x)   ans[cmd[i].id].mol = 0,ans[cmd[i].id].den = 1;
            else{
                ll tem = gcd(x,y);
                ans[cmd[i].id].mol = x/tem;
                ans[cmd[i].id].den = y/tem;
            }
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            memset(cnt,0,sizeof(cnt));
            FOR(i,1,n+1)    scanf("%d",&col[i]);
            FOR(i,0,m){
                scanf("%lld%lld",&cmd[i].l,&cmd[i].r);
                cmd[i].id = i;
            }
            sort(cmd,cmd+m);
            solve();
            FOR(i,0,m){
                printf("%lld/%lld
    ",ans[i].mol,ans[i].den);
            }
        }
        return 0;
    }
    2:Sona https://ac.2333.moe/Problem/view.xhtml?id=1457 

    这道题给人一种然并卵的感觉,和上题基本一样

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <map>
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define ll long long
    #define N 100100
    
    using namespace std;
    
    const int M = (int)sqrt(1.0*N);
    int n,m;
    ll cnt[N],col[N];
    ll ans[N];
    
    struct Col{
        ll note;
        int id;
        bool operator < (const Col& rhs) const{
            return note < rhs.note;
        }
    }con[N];
    
    struct Commend{
        int l,r;
        int id;
        bool operator < (const Commend& rhs)  const{
            if(l/M == rhs.l/M)  return r < rhs.r;
            return (l/M) < (rhs.l/M);
        }
    }cmd[N];
    
    void solve(){
        int L = 1,R = 0;
        FOR(i,0,N)  cnt[i] = 0;
        ll temp = 0;
        FOR(i,0,m){
            while(R < cmd[i].r){
                R ++;
                temp -= cnt[col[R]]*cnt[col[R]]*cnt[col[R]];
                cnt[col[R]] ++;
                temp += cnt[col[R]]*cnt[col[R]]*cnt[col[R]];
            }
            while(R > cmd[i].r){
                temp -= cnt[col[R]]*cnt[col[R]]*cnt[col[R]];
                cnt[col[R]] --;
                temp += cnt[col[R]]*cnt[col[R]]*cnt[col[R]];
                R --;
            }
            while(L < cmd[i].l){
                temp -= cnt[col[L]]*cnt[col[L]]*cnt[col[L]];
                cnt[col[L]] --;
                temp += cnt[col[L]]*cnt[col[L]]*cnt[col[L]];
                L ++;
            }
            while(L > cmd[i].l){
                L --;
                temp -= cnt[col[L]]*cnt[col[L]]*cnt[col[L]];
                cnt[col[L]] ++;
                temp += cnt[col[L]]*cnt[col[L]]*cnt[col[L]];
            }
            ans[cmd[i].id] = temp;
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d",&n)){
            FOR(i,0,n)    {scanf("%I64d",&con[i].note);con[i].id = i+1;}
            sort(con,con+n);
            int cot = 0;
            col[con[0].id] = (++cot);
            FOR(i,1,n){
                if(con[i].note != con[i-1].note)    col[con[i].id] = (++cot);
                else col[con[i].id] = cot;
            }
            scanf("%d",&m);
            FOR(i,0,m){
                scanf("%d%d",&cmd[i].l,&cmd[i].r);
                cmd[i].id = i;
            }
            sort(cmd,cmd+m);
            solve();
            FOR(i,0,m){
                printf("%I64d
    ",ans[i]);
            }
        }
        return 0;
    }

    3:Group http://acm.hdu.edu.cn/showproblem.php?pid=4638 维护一个左边数的位置,右边数的位置,1,n特判一下就行了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define ll long long
    #define N 100010
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    
    using namespace std;
    
    const int M = (int)sqrt(1.0*N);
    int num[N],pos[N],ans[N],l[N],r[N];
    int n,m;
    
    struct Commend{
        int l,r;
        int id;
        bool operator < (const Commend& rhs) const{
            if(l/M == rhs.l/M)  return r < rhs.r;
            return (l/M < rhs.l/M);
        }
    }cmd[N];
    
    void solve(){
        int L = 1,R = 0;
        int temp = 0;
        FOR(i,0,m){
            while(R < cmd[i].r){
                R ++;
                if(l[num[R]] >= L && r[num[R]] <= R) temp --;
                else if((l[num[R]] < L && r[num[R]] > R) || (l[num[R]] > R) || (r[num[R]] < L))   temp ++;
            }
            while(R > cmd[i].r){
                if(l[num[R]] >= L && r[num[R]] <= R)  temp ++;
                else if((l[num[R]] < L && r[num[R]] > R) || (l[num[R]] > R) || (r[num[R]] < L))   temp --;
                R --;
            }
            while(L < cmd[i].l){
                if(l[num[L]] >= L && r[num[L]] <= R)  temp ++;
                else if((l[num[L]] < L && r[num[L]] > R)  || (l[num[L]] > R) || (r[num[L]] < L))  temp --;
                L ++;
            }
            while(L > cmd[i].l){
                L --;
                if(l[num[L]] >= L && r[num[L]] <= R) temp --;
                else if((l[num[L]] < L && r[num[L]] > R)  || (l[num[L]] > R) || (r[num[L]] < L))  temp ++;
            }
            ans[cmd[i].id] = temp;
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            FOR(i,1,n+1){
                scanf("%d",&num[i]);
                pos[num[i]] = i;
            }
            l[1] = 0;
            r[1] = pos[2];
            r[n] = n+1;
            l[n] = pos[n-1];
            FOR(i,2,n){
               l[i] = min(pos[i-1],pos[i+1]);
               r[i] = max(pos[i-1],pos[i+1]);
            }
            FOR(i,0,m){
                scanf("%d%d",&cmd[i].l,&cmd[i].r);
                cmd[i].id = i;
            }
            sort(cmd,cmd+n);
            solve();
            FOR(i,0,m){
                printf("%d
    ",ans[i]);
            }
        }
        return 0;
    }
    

    4:Zero Query http://www.spoj.com/problems/ZQUERY/en/ 我wa到死的一题。这个题要维护一个左边最靠近的一个位置,右边靠近的一个位置,就行了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <map>
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define lrt rt<<1
    #define rrt rt<<1|1
    #define lson rt<<1,l,mid
    #define rson rt<<1|1,mid+1,r
    #define ll long long
    #define N 50050
    
    using namespace std;
    
    int M;
    int cnt,col[N],sum[N],n,m,l[N],r[N],st,pr[N],pl[N],ans[N],pos[N];
    int maxn,minn;
    
    struct Commend{
        int l,r;
        int id;
        bool operator < (const Commend& rhs) const{
            if(l/M == rhs.l/M)  return r < rhs.r;
            return (l/M) < (rhs.l/M);
        }
    }cmd[N];
    
    struct Tree{
        int l,r;
        int maxx;
    }tree[N<<2];
    
    void Build(int rt,int l,int r){
        tree[rt].l = l; tree[rt].r = r; tree[rt].maxx = 0;
        if(l == r) return;
        int mid = (l+r)>>1;
        Build(lson);
        Build(rson);
    }
    
    void PushUp(int rt) {tree[rt].maxx = max(tree[lrt].maxx,tree[rrt].maxx);}
    
    void Modify(int rt,int k,int val){
        if(tree[rt].l == tree[rt].r)    {tree[rt].maxx = val;return;}
        int mid = (tree[rt].l + tree[rt].r)>>1;
        if(k <= mid)    Modify(lrt,k,val);
        else Modify(rrt,k,val);
        PushUp(rt);
    }
    
    void solve(){
        int L = 1,R = 0;
        memset(r,-1,sizeof(r));
        memset(l,-1,sizeof(l));
        FOR(i,0,m){
            while(R < cmd[i].r){
                R ++;
                if(l[col[R]] == -1) l[col[R]] = R;
                r[col[R]] = R;
                Modify(1,col[R],r[col[R]]-l[col[R]]);
            }
            while(R > cmd[i].r){
                r[col[R]] = pr[R];
                if(r[col[R]] < L)   l[col[R]] = r[col[R]] = -1;
                Modify(1,col[R],r[col[R]]-l[col[R]]);
                R --;
            }
            while(L < cmd[i].l){
                l[col[L]] = pl[L];
                if(l[col[L]] > R || l[col[L]] == -1)   l[col[L]] = r[col[L]] = -1;
                Modify(1,col[L],r[col[L]]-l[col[L]]);
                L ++;
            }
            while(L > cmd[i].l){
                L --;
                if(r[col[L]] == -1) r[col[L]] = L;
                l[col[L]] = L;
                Modify(1,col[L],r[col[L]]-l[col[L]]);
            }
            ans[cmd[i].id] = tree[1].maxx;
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            M = (int)sqrt(1.0*n);
            int tem;
            sum[1] = col[1] = 0;
            maxn = minn = 0;
            FOR(i,2,n+2){
                scanf("%d",&tem);
                sum[i] = sum[i-1] + tem;
                if(tem == 1) maxn = max(maxn,sum[i]);
                else minn = min(minn,sum[i]);
            }
            cnt = 1-minn;
            FOR(i,1,n+2){
                col[i] = sum[i] + cnt;
            }
            cnt = maxn-minn+1;
            Build(1,1,cnt);
            FOR(i,0,m){
                scanf("%d%d",&cmd[i].l,&cmd[i].r);
                cmd[i].r ++;
                cmd[i].id = i;
            }
            sort(cmd,cmd+m);
            FOR(i,1,cnt+1)  pos[i] = -1;
            FOR(i,1,n+2){
                pr[i] = pos[col[i]];
                pos[col[i]] = i;
            }
            FOR(i,1,cnt+1)  pos[i] = -1;
            IFOR(i,n+1,0){
                pl[i] = pos[col[i]];
                pos[col[i]] = i;
            }
            solve();
            FOR(i,0,m){
                printf("%d
    ",ans[i]);
            }
        }
        return 0;
    }
    5:The sum of gcd http://acm.hdu.edu.cn/showproblem.php?pid=5381 和上一题有点像,稍微复杂一点,可以看我这道题写的题解

    http://blog.csdn.net/u014610830/article/details/47670615

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    (0.12)elasticsearch分布式集群原理(ES7.9)
    (0.9)elasticsearch分布式集群概念
    mysql分库分表【转】
    (0.11)elasticsearch常用查询,REST API的基本约定,ES增删查改
    mysql全日志自动化脚本
    Java虚拟机--类加载的过程
    Java虚拟机--运行时数据区域
    新题型|结构不良题
    恒等变形的是与非
    分形图与二阶数列
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4811892.html
Copyright © 2011-2022 走看看