zoukankan      html  css  js  c++  java
  • P1972 [SDOI2009] HH的项链(莫队)

    https://www.luogu.org/problem/show?pid=1972#sub
    时间复杂度证明:

    右端点移动:
    首先我们考虑一个块里面的转移情况
    由于一个块里面的询问都按右端点排序
    所以我们右端点在一个块里面最多移动n次
    有 O(n√)O(n)个块,那么同一个块内的右端点移动最多就是O(nn√)O(nn)
    然后考虑从一个块到另一个块导致的右端点变化
    最坏情况,右端点由n到1,那么移动n次
    有 O(n√)O(n)个块
    那么从一个块到另一个块的事件只会发生O(n√)O(n)次……
    所以这种右端点移动的次数也是O(nn√)O(nn)次
    没有别的事件导致右端点移动了
    左端点移动:
    同一个块里面,由于左端点都在一个长度为O(n√)O(n)的区间里面
    所以在同一块里面移动一次,左端点最多变化O(n√)O(n)
    总共有n个询问……
    所以同一块里面的移动最多n次
    那么同一个块里面的左端点变化最多是O(nn√)O(nn)的
    考虑跨越块
    每由第i个块到第i+1个块,左端点最坏加上O(n√)O(n)
    总共能加上O(n√)O(n)次
    所以跨越块导致的左端点移动是O(n)O(n)的
    综上,分块做法是O(n∗n√)O(n∗n)。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct H{
        int l,r,id,qv;
    }Q[200009];
    int a[50009],n,m,limit,sum=0;
    int num[1000009],ans[200009];
    int my_comp(const H&a,const H&b)
    {
        if(a.qv<b.qv) return 1;//根据左端点分块
        if(a.qv>b.qv) return 0;
        if(a.r<b.r) return 1;//在块内按照r升序
        return 0;
    }
    void add(int x)
    {
        num[x]++;
        if(num[x]==1) sum++;//
    }
    void del(int x)
    {
        num[x]--;
        if(num[x]==0) sum--;//
    }
    int main()
    {
        scanf("%d",&n);limit=(int)(sqrt((double)(n)+0.5));
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&a[i]); 
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&Q[i].l,&Q[i].r);
            Q[i].qv=Q[i].l/limit;Q[i].id=i;//id 为第几个询问,离线输出
        }
    
        sort(Q+1,Q+m+1,my_comp);
    
        int r=0,l=0;
        for(int i=1;i<=m;i++)
        {
            while(r<Q[i].r){
                r++;
                add(a[r]);
            }
            while(r>Q[i].r){
                r--;
                del(a[r+1]);
            }
            while(l<Q[i].l){
                l++;
                del(a[l-1]);
            }
            while(l>Q[i].l){
                l--;
                add(a[l]);
            }
            ans[Q[i].id]=sum;
        }
        for(int i=1;i<=m;i++)
        {
            printf("%d
    ",ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    Js获取时间,当前,一周前,一月前的时间,时间戳转换,时间格式化,日期格式化
    echarts图随窗口大小的变化而变化
    Vue中使用Google地图插件
    element el-progress渐变色进度条
    Vue中使用mixins
    CSS3 使用 calc() 计算高度 vh px
    element-ui饿了么框架中导航菜单中箭头方向问题
    Vue中使用QRcode.js生成二维码---qrcodejs2
    鼠标经过时显示样式的两种方法
    element 按钮样式:确认按钮发布后样式发生改变
  • 原文地址:https://www.cnblogs.com/dfsac/p/6819739.html
Copyright © 2011-2022 走看看