zoukankan      html  css  js  c++  java
  • 莫队+带修莫队模板与总结

    以下总结参考了许多大佬们的博客,开篇先(大佬)%

    莫队的入门题目主要为莫队和带修莫队在,这里就先在这里总结一下这两类题目的一些属性。

    我认为莫队本质是一种比较优化的暴力查找法。在通过分块操作后把复杂度降低。这个降低的复杂度的大小主要和你分块的方法有着巨大的关系。

    普通的莫队,n个元素m个区间询问,他的最佳分块大小为  n/√m   ,如果默认n==m的话  复杂度会降到 O(n*√n)  即可以完美运行5X10e5数据。

    带修的莫队,多加了一个让指针移动的因子—时间 t  ,时间复杂度比较难求,如果设定n,m,t相等的情况下 复杂度O(nlogn+n5/3),同样可以运行50000数据。

    贴两道经典的莫队存板子。

    P1494 [国家集训队]小Z的袜子 https://www.luogu.org/problemnew/show/P1494

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    ll b,ans=0;int l=1,r=0;
    ll gcd(ll a,ll b)
    {
        if(b==0) return a;
        else return gcd(b,a%b);
    }
    struct dd
    {
        int x,y,num;
    }a[50050];
    ll cmp(dd x,dd y)
    {
        if(x.x/b==y.x/b) return x.y<y.y;
        else return x.x<y.x;
    }
    ll bj[50050]={0};
    ll c[50050];
    pair<int,int> pr[50050];
    void solve(int x,int add)
    {
        ans-=bj[c[x]]*bj[c[x]];
        //cout<<ans<<endl;
        bj[c[x]]+=add;
        ans+=bj[c[x]]*bj[c[x]];
        //cout<<ans<<endl;
    }
    int main()
    {
        ll n,m,q,i,j;
        scanf("%lld%lld",&n,&q);
        b=sqrt(n);
        for(i=1;i<=n;i++) scanf("%lld",&c[i]);
        for(i=1;i<=q;i++) scanf("%d%d",&a[i].x,&a[i].y),a[i].num=i;
        sort(a+1,a+q+1,cmp);
         
        for(i=1;i<=q;i++)
        {
            ll lon=a[i].y-a[i].x+1;
            //cout<<a[i].x<<" "<<a[i].y<<"lon="<<lon<<endl;
            while(l<a[i].x)
            {
                solve(l,-1);l++;
            }
            while(l>a[i].x)
            {
                solve(l-1,1);l--;
            }
            while(r<a[i].y)
            {
                solve(r+1,1);r++;
            }
            while(r>a[i].y)
            {
                solve(r,-1);r--;
            }
            //cout<<l<<" "<<r<<endl;
            int aans=ans-lon;
            lon=lon*(lon-1);
            int gc=gcd(aans,lon);
            //cout<<ans<<" "<<lon<<endl;
            if(aans==0) pr[a[i].num].first=0,pr[a[i].num].second=1;
            else pr[a[i].num].first=aans/gc,pr[a[i].num].second=lon/gc;
        }
        for(i=1;i<=q;i++) printf("%d/%d
    ",pr[i].first,pr[i].second);
    }

    P1903 [国家集训队]数颜色 / 维护队列 https://www.luogu.org/problemnew/show/P1903

    #include<bits/stdc++.h>
    using namespace std;
    int ans=0;int l=1,r=0,t=0;
    int b;
    struct dd
    {
        int x,y,t,num;
    }a[50050];
    struct dt
    {
        int p, v;
    }tw[50050];
    int cmp(dd x,dd y)
    {
        if(x.x/b==y.x/b)
        {
            if(x.y/b==y.y/b) return x.t<y.t;
            return x.y/b<y.y/b;
         } 
        else return x.x<y.x;
    }
    int bj[1000050]={0};
    int e=0,tim=0;
    int c[50050];
    int pr[50050];
    void solve(int x,int add)
    {
        bj[c[x]]+=add;
        if(bj[c[x]]==0&&add==-1) ans--;
        if(bj[c[x]]==1&&add==1) ans++;
        //cout<<ans<<endl;
    }
    void time_change(int i,int tt)
    {
        if(tw[tt].p>=a[i].x&&tw[tt].p<=a[i].y) 
        {
            bj[c[tw[tt].p]]--;
            if(bj[c[tw[tt].p]]==0) ans--;
            bj[tw[tt].v]++;
            if(bj[tw[tt].v]==1) ans++;
        }
        swap(tw[tt].v,c[tw[tt].p]);
    }
    int main()
    {
        int n,q,i;
        char qq[5];
        scanf("%d%d",&n,&q);
        b=pow(n,0.66666);
        for(i=1;i<=n;i++) scanf("%d",&c[i]);
        for(i=1;i<=q;i++) 
        {
            scanf("%s",qq);
            if(qq[0]=='Q')
            {
                e++;
                scanf("%d%d",&a[e].x,&a[e].y);
                a[e].t=tim;
                a[e].num=e;
            }
            else
            {
                tim++;
                scanf("%d%d",&tw[tim].p,&tw[tim].v);
            }
        }
        sort(a+1,a+e+1,cmp);
        
        for(i=1;i<=e;i++)
        {
            //cout<<a[i].x<<" "<<a[i].y<<"lon="<<lon<<endl;
            while(l<a[i].x)
            {
                solve(l,-1);l++;
            }
            while(l>a[i].x)
            {
                solve(l-1,1);l--;
            }
            while(r<a[i].y)
            {
                solve(r+1,1);r++;
            }
            while(r>a[i].y)
            {
                solve(r,-1);r--;
            }
            //cout<<l<<" "<<r<<endl;
            while(t<a[i].t)
            {
                time_change(i,t+1);
                t++;
            }
            while(t>a[i].t)
            {
                time_change(i,t);
                t--;
            }
            //cout<<ans<<" "<<lon<<endl;
            pr[a[i].num]=ans;
        }
        for(i=1;i<=e;i++) printf("%d
    ",pr[i]);
    }
  • 相关阅读:
    静态初始化块和main方法哪个先被执行?
    Java中的构造方法
    Java中的局部变量、成员变量和静态变量
    经典算法冒泡排序java版
    Java里数组的三种初始化方式
    聊天,发朋友圈可以不打字,但是表情怎么能少呢?那么如何用win10自带的微软拼音输入法打出表情呢?
    java打印实心10*10正方形, 空心10*10正方形
    安卓工程目录
    (1)开源中国android客户端源码分析
    认识电脑的开机流程与主引导分区(MBR)
  • 原文地址:https://www.cnblogs.com/wsblm/p/10813007.html
Copyright © 2011-2022 走看看