zoukankan      html  css  js  c++  java
  • bzoj 2038 莫队算法

    莫队算法,具体的可以看10年莫涛的论文。

    大题思路就是假设对于区间l,r我们有了一个答案,那么对于区间l,r+1,我们

    可以暴力的转移一个答案,那么对于区间l1,r1和区间l2,r2,需要暴力处理

    的部分就是|r1-r2|+|l1-l2|如果将l看成x,r看成r,得到的暴力部分就是manhattan距离

    那么我们将所有的询问,构成一张二维图,可以从一个点转移到另一个点,且总manhattan距离

    尽可能的小,所以可以建立一颗manhattan mst,这样的话就可以得到最优的转移,但是实际来说

    搞定一个manhattan mst需要的时间不小,我们可以不要最优解,将询问按l分块,只需要做到在每个

    块中尽可能的优就行了,所以每个块中可以根据r排序,然后搞就行了

    经莫队证明,这个算法的复杂度上界大概是o(n^1.5)

    /**************************************************************
        Problem: 2038
        User: BLADEVIL
        Language: Pascal
        Result: Accepted
        Time:3164 ms
        Memory:2572 kb
    ****************************************************************/
     
    //By BLADEVIL
    type
        rec                         =record
            l, r, w, s              :longint;
        end;
         
    var
     
        n, m                        :longint;
        c, size                     :array[0..50010] of int64;
        len                         :longint;
        a                           :array[0..50010] of rec;
        now                         :longint;
        col, ans                    :array[0..50010] of int64;
        all, num                    :int64;
         
    procedure swap(var a,b:longint);
    var
        c                           :longint;
    begin
        c:=a; a:=b; b:=c;
    end;
     
    procedure swap_rec(var a,b:rec);
    var
        c                           :rec;
    begin
        c:=a; a:=b; b:=c;
    end;
     
    function gcd(a,b:int64):int64;
    begin
        if a<b then exit(gcd(b,a)) else
        if b=0 then exit(a) else exit(gcd(b,a mod b));
    end;
     
    procedure qs(low,high:longint);
    var
        i, j, xx, yy                :longint;
    begin
        i:=low; j:=high; xx:=a[(i+j) div 2].w;
        yy:=a[(i+j) div 2].r;
        while i<j do
        begin
            while (a[i].w<xx) or (a[i].w=xx) and (a[i].r<yy) do inc(i);
            while (a[j].w>xx) or (a[j].w=xx) and (a[j].r>yy) do dec(j);
            if i<=j then
            begin
                swap_rec(a[i],a[j]);
                inc(i); dec(j);
            end;
        end;
        if i<high then qs(i,high);
        if j>low then qs(low,j);
    end;
         
    procedure init;
    var
        i                           :longint;
         
    begin
        read(n,m);
        for i:=1 to n do read(c[i]);
        len:=trunc(sqrt(m));
        for i:=1 to m do
        begin
            read(a[i].l,a[i].r);
            if a[i].l>a[i].r then swap(a[i].l,a[i].r);
            size[i]:=a[i].r-a[i].l+1;
            a[i].w:=a[i].l div len+1;
            a[i].s:=i;
        end;
        qs(1,m);
    end;
         
    procedure main;
    var
        i, j                        :longint;
    begin
        i:=1;
        while i<=m do
        begin
            now:=a[i].w;
            fillchar(col,sizeof(col),0);
            for j:=a[i].l to a[i].r do
            begin
                ans[a[i].s]:=ans[a[i].s]+2*(col[c[j]]);
                col[c[j]]:=col[c[j]]+1;
            end;
            inc(i);
            while a[i].w<=now do
            begin
                ans[a[i].s]:=ans[a[i-1].s];
                for j:=a[i-1].r+1 to a[i].r do
                begin
                    ans[a[i].s]:=ans[a[i].s]+2*(col[c[j]]);
                    col[c[j]]:=col[c[j]]+1;
                end;
                if a[i-1].l<a[i].l then
                begin
                    for j:=a[i-1].l to a[i].l-1 do
                    begin
                        col[c[j]]:=col[c[j]]-1;
                        ans[a[i].s]:=ans[a[i].s]-2*col[c[j]];
                    end;
                end else
                    for j:=a[i].l to a[i-1].l-1 do
                    begin
                        ans[a[i].s]:=ans[a[i].s]+2*(col[c[j]]);
                        col[c[j]]:=col[c[j]]+1;
                    end;
                inc(i);
                if i>m then break;
            end;
        end;
        for i:=1 to m do
        begin
            if size[i]=1 then all:=1 else all:=size[i]*(size[i]-1);
            num:=gcd(ans[i],all);
            writeln(ans[i] div num,'/',all div num);
        end;
    end;
         
         
    begin
        init;
        main;
    end.
  • 相关阅读:
    C++ 指针 new delete int*与string
    61.Android适配的那些P事(转)
    60.Android通用流行框架大全
    Android Studio配置指南总结
    大数据学习资源(下)
    大数据学习资源(上)
    59.Android开源项目及库 (转)
    Linux 简介
    7款应用最广泛的Linux桌面环境盘点
    58. Android一些开发习惯总结
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3496774.html
Copyright © 2011-2022 走看看