zoukankan      html  css  js  c++  java
  • 莫队

     又开坑

    2015.2.15填坑开始

    写在前面的废话

       莫队是用于一些离线区间查询问题的,比如查询某个区间内某个值有多少个,这类问题用数据结构做十分麻烦(其实是蒟蒻不会)。在处理带修改的区间总和问题时可以通过分治大法来达到比较好的结果。而莫队,就是一种神奇的分治大法。

    具体做法:

    前人之述备已,下面给学习的链接。

    链接:

    一份不错的总结:http://blog.csdn.net/mlzmlz95/article/details/43644653

    苹果树很好的题解:

    http://www.cnblogs.com/zyfzyf/p/4250029.html

    http://naginikaido.github.io/2015/01/09/bzoj3757-%E8%8B%B9%E6%9E%9C%E6%A0%91-%E6%A0%91%E4%B8%8A%E8%8E%AB%E9%98%9F/

    糖果公园很好的题解

    http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

    自己的一些废话

    莫队其实就是先对区间进行分类,把左端分成一块一块,然后保证快内的右端点单调递增。然后按照这个顺序进行暴力转移(多退少补)。

    而树上的莫队就是如何构造出这个块,亲身试验是如果直接用dfs序暴力会慢到要死,而vfk大大的神奇分发会快很多(虽然还是比c++慢)。

    具体做法就是记录当前节点的儿子数,如果儿子数超过了块的大小就单独变成一块,剩下的几个儿子和孙子连同这个节点上到上一个节点的块中。

    然后访问到某个点时存在性取反,最后答案要算上lca

    function dfs(x:longint):longint;
    var
      size,i,too,j:longint;
    begin
      size:=0;
      inc(time);
      dfn[x]:=time;
      for i:=1 to 16 do begin
        j:=fa[fa[x,i-1],i-1];
        if j>0 then
          fa[x,i]:=j
        else break;
      end;
      i:=first[x];
      while i>0 do begin
        too:=edge[i].toward;
        if too<>fa[x,0] then begin
          deep[too]:=deep[x]+1;
          fa[too,0]:=x;
          inc(size,dfs(too));
          if size>=long then begin
            inc(total);
            while size>0 do begin
              block[p[top]]:=total;
              dec(size);
              dec(top);
            end;
          end;
        end;
        i:=edge[i].next;
      end;
      inc(top);
      p[top]:=x;
      exit(size+1)
    end;
    View Code

    不带修改就双关键字排序,带修改就三关键字排序。

    小Z的袜子

    模板题

    bzoj3781:小B的询问

    模板题

    type
      arr=record
        left,right,pl,num:longint;
      end;
    var
      tot,col,ans:array[0..600000]of longint;
      ask:array[0..600000]of arr;
      long,n,m,kk:longint;
     
    procedure qsort(l,r:longint);
    var
      i,j,mid1,mid2:longint;
      tmp:arr;
    begin
      mid1:=ask[(l+r)>>1].num;
      mid2:=ask[(l+r)>>1].right;
      i:=l;
      j:=r;
      repeat
        while (mid1>ask[i].num) or (mid1=ask[i].num) and (mid2>ask[i].right) do inc(i);
        while (mid1<ask[j].num) or (mid1=ask[j].num) and (mid2<ask[j].right) do dec(j);
        if i<=j then begin
          tmp:=ask[i];
          ask[i]:=ask[j];
          ask[j]:=tmp;
          inc(i);
          dec(j);
        end;
      until i>j;
      if i<r then qsort(i,r);
      if l<j then qsort(l,j);
    end;
     
     
    procedure into;
    var
      i,j,k:longint;
    begin
      readln(n,m,kk);
      for i:=1 to n do read(col[i]);
      long:=trunc(sqrt(m));
      for i:=1 to m do begin
        readln(ask[i].left,ask[i].right);
        ask[i].num:=ask[i].left div long+1;
        ask[i].pl:=i;
      end;
      qsort(1,m);
    end;
     
    procedure work;
    var
      l,r,i,j,sum:longint;
    begin
      fillchar(tot,sizeof(tot),0);
      sum:=0;
      l:=1;
      r:=0;
      for i:=1 to m do begin
        for j:=r+1 to ask[i].right do begin
          sum:=sum+tot[col[j]]*2+1;
          inc(tot[col[j]]);
        end;
        for j:=r downto ask[i].right+1 do begin
          sum:=sum-tot[col[j]]*2+1;
          dec(tot[col[j]]);
        end;
        for j:=l-1 downto ask[i].left do begin
          sum:=sum+tot[col[j]]*2+1;
          inc(tot[col[j]]);
        end;
        for j:=l to ask[i].left-1 do begin
          sum:=sum-tot[col[j]]*2+1;
          dec(tot[col[j]]);
        end;
        ans[ask[i].pl]:=sum;
        l:=ask[i].left;
        r:=ask[i].right;
      end;
      for i:=1 to m do
        writeln(ans[i]);
    end;
     
    begin
      into;
      work;
    end.
    View Code

    bzoj3757: 苹果树

    树上莫队模板题:树上就是状态取反,然后答案要算上lca再减掉lca

    type
      arr1=record
        u,v,a,b,pl:longint;
      end;
      arr2=record
        toward,next:longint;
      end;
     
    const
      maxn=500000;
     
    var
      fa:array[0..maxn,0..18]of longint;
      edge:array[0..maxn]of arr2;
      ask:array[0..maxn]of arr1;
      ans,first,deep,dfn,num,p,fft,much,col:array[0..maxn]of longint;
      pow:array[0..18]of longint;
      chose:array[0..maxn]of boolean;
      esum,top,sum,time,n,m,long,total,root:longint;
     
    procedure addedge(i,j:longint);
    begin
      inc(esum);
      edge[esum].toward:=j;
      edge[esum].next:=first[i];
      first[i]:=esum;
      inc(esum);
      edge[esum].toward:=i;
      edge[esum].next:=first[j];
      first[j]:=esum;
    end;
     
    procedure swap(var x,y:longint);
    var
      i:longint;
    begin
      i:=x;
      x:=y;
      y:=i;
    end;
     
    function dfs(x:longint):longint;
    var
      size,i,too,j:longint;
    begin
      inc(time);
      dfn[x]:=time;
      for i:=1 to 15 do
        if deep[x]>=pow[i] then fa[x,i]:=fa[fa[x,i-1],i-1]
          else break;
      size:=0;
      i:=first[x];
      while i>0 do begin
        too:=edge[i].toward;
        if too<>fa[x,0] then begin
          deep[too]:=deep[x]+1;
          fa[too,0]:=x;
          inc(size,dfs(too));
          if size>=long then begin
            inc(total);
            while size>0 do begin
              num[p[top]]:=total;
              dec(top);
              dec(size);
            end;
          end;
        end;
        i:=edge[i].next;
      end;
      inc(top);
      p[top]:=x;
      exit(size+1)
    end;
     
    procedure qsort(l,r:longint);
    var
      i,j,mid1,mid2,k:longint;
      tmp:arr1;
    begin
      i:=l;
      j:=r;
      k:=random(r-l)+l;
      mid1:=num[ask[k].u];
      mid2:=dfn[ask[k].v];
      repeat
        while (num[ask[i].u]<mid1) or (num[ask[i].u]=mid1) and (dfn[ask[i].v]<mid2) do inc(i);
        while (num[ask[j].u]>mid1) or (num[ask[j].u]=mid1) and (dfn[ask[j].v]>mid2) do dec(j);
        if i<=j then begin
          tmp:=ask[i];
          ask[i]:=ask[j];
          ask[j]:=tmp;
          inc(i);
          dec(j);
        end;
      until i>j;
      if i<r then qsort(i,r);
      if l<j then qsort(l,j)
    end;
     
    function lca(x,y:longint):longint;
    var
      max,i,j:longint;
    begin
      if deep[x]<deep[y] then swap(x,y);
      i:=0;
      j:=deep[x]-deep[y];
      while pow[i]<=j do begin
        if j and pow[i]>0 then x:=fa[x,i];
        inc(i);
      end;
      if x=y then exit(x);
      for i:=15 downto 0 do
        if (fa[x,i]<>fa[y,i]) then begin
          x:=fa[x,i];
          y:=fa[y,i];
        end;
      exit(fa[x,0])
    end;
     
    procedure change(x:longint);
    begin
      if not chose[x] then begin
        inc(much[col[x]]);
        if much[col[x]]=1 then inc(sum);
      end
      else begin
        dec(much[col[x]]);
        if much[col[x]]=0 then dec(sum);
      end;
      chose[x]:=not chose[x]
    end;
     
    procedure solve(x,y:longint);
    begin
      while x<>y do
        if deep[x]>deep[y] then begin
          change(x);
          x:=fa[x,0];
        end
        else begin
          change(y);
          y:=fa[y,0];
        end
    end;
     
    procedure into;
    var
      i,j,k:longint;
    begin
      pow[0]:=1;
      for i:=1 to 16 do pow[i]:=pow[i-1]<<1;
      readln(n,m);
      long:=trunc(sqrt(n*ln(n)/ln(2)));
      for i:=1 to n do read(col[i]);
      for i:=1 to n do begin
        readln(j,k);
        if j=0 then root:=k
        else
        if k=0 then root:=j
        else
        addedge(j,k);
      end;
      time:=0;
      deep[root]:=1;
      dfs(root);
      if top>0 then begin
        inc(total);
        for i:=1 to top do
          num[p[i]]:=total;
      end;
      for i:=1 to m do begin
        read(ask[i].u,ask[i].v,ask[i].a,ask[i].b);
        if dfn[ask[i].u]>dfn[ask[i].v] then swap(ask[i].u,ask[i].v);
        ask[i].pl:=i;
      end;
      qsort(1,m)
    end;
     
    procedure work;
    var
      i,j:longint;
    begin
      sum:=0;
      solve(ask[1].u,ask[1].v);
      j:=lca(ask[1].u,ask[1].v);
      change(j);
      ans[ask[1].pl]:=sum;
      if (much[ask[1].a]>0) and (much[ask[1].b]>0) and (ask[1].a<>ask[1].b) then dec(ans[ask[1].pl]);
      change(j);
      for i:=2 to m do begin
        solve(ask[i-1].u,ask[i].u);
        solve(ask[i-1].v,ask[i].v);
        j:=lca(ask[i].u,ask[i].v);
        change(j);
        ans[ask[i].pl]:=sum;
        if (much[ask[i].a]>0) and (much[ask[i].b]>0) and (ask[i].a<>ask[i].b) then dec(ans[ask[i].pl]);
        change(j);
      end;
      for i:=1 to m do writeln(ans[i])
    end;
     
    Begin
      into;
      work;
    end.
    View Code

    bzoj3052: [wc2013]糖果公园

    太神了直接跪vkf大神的题解吧!

    type
      arr1=record
        toward,next:longint;
      end;
      arr2=record
        new,old,pl:longint;
      end;
      arr3=record
        u,v,pl,t:longint;
      end;
    
    const
      maxn=200020;
    
    var
      edge:array[0..maxn]of arr1;
      ask1:array[0..maxn]of arr2;
      ask2:array[0..maxn]of arr3;
      first,deep,belong,dfn,pre,value,w,col,much,block,p:array[0..maxn]of longint;
      ans:array[0..maxn]of int64;
      fa:array[0..maxn,0..16]of longint;
      chose:array[0..maxn]of boolean;
      tot1,tot2,esum,total,time,n,m,long,top:longint;
      sum:int64;
    
    procedure swap(var x,y:longint);
    var
      i:longint;
    begin
      i:=x;
      x:=y;
      y:=i;
    end;
    
    procedure addedge(j,k:longint);
    begin
      inc(esum);
      edge[esum].toward:=k;
      edge[esum].next:=first[j];
      first[j]:=esum;
    end;
    
    function dfs(x:longint):longint;
    var
      size,i,too,j:longint;
    begin
      size:=0;
      inc(time);
      dfn[x]:=time;
      for i:=1 to 16 do begin
        j:=fa[fa[x,i-1],i-1];
        if j>0 then
          fa[x,i]:=j
        else break;
      end;
      i:=first[x];
      while i>0 do begin
        too:=edge[i].toward;
        if too<>fa[x,0] then begin
          deep[too]:=deep[x]+1;
          fa[too,0]:=x;
          inc(size,dfs(too));
          if size>=long then begin
            inc(total);
            while size>0 do begin
              block[p[top]]:=total;
              dec(size);
              dec(top);
            end;
          end;
        end;
        i:=edge[i].next;
      end;
      inc(top);
      p[top]:=x;
      exit(size+1);
    end;
    
    function check(x,y:arr3):boolean;
    begin
      if block[x.u]<block[y.u] then exit(true);
      if block[x.u]>block[y.u] then exit(false);
    
      if block[x.v]<block[y.v] then exit(true);
      if block[x.v]>block[y.v] then exit(false);
    
      if x.t<y.t then exit(true);
      exit(false);
    end;
    
    procedure qsort(l,r:longint);
    var
      i,j:longint;
      mid,tmp:arr3;
    begin
      i:=l;
      j:=r;
      mid:=ask2[(l+r)>>1];
      repeat
        while check(ask2[i],mid) do inc(i);
        while check(mid,ask2[j]) do dec(j);
        if i<=j then begin
          tmp:=ask2[i];
          ask2[i]:=ask2[j];
          ask2[j]:=tmp;
          inc(i);
          dec(j);
        end;
      until i>j;
      if i<r then qsort(i,r);
      if l<j then qsort(l,j);
    end;
    
    function lca(x,y:longint):longint;
    var
      i:longint;
    begin
      if deep[x]<deep[y] then swap(x,y);
      for i:=16 downto 0 do
        if deep[fa[x,i]]>=deep[y] then
          x:=fa[x,i];
      if x=y then exit(x);
      for i:=16 downto 0 do
        if fa[x,i]<>fa[y,i] then begin
          x:=fa[x,i];
          y:=fa[y,i];
        end;
      exit(fa[x,0]);
    end;
    
    procedure reverse(x:longint);
    begin
      if chose[x] then begin
        sum:=sum-int64(w[much[col[x]]])*value[col[x]];
        dec(much[col[x]]);
      end
      else begin
        inc(much[col[x]]);
        sum:=sum+int64(w[much[col[x]]])*value[col[x]];
      end;
      chose[x]:=not chose[x];
    end;
    
    procedure change(x,y:longint);
    begin
      if chose[x] then begin
        reverse(x);
        col[x]:=y;
        reverse(x);
      end
      else col[x]:=y;
    end;
    
    procedure solve(x,y:longint);
    begin
      while x<>y do
        if deep[x]>deep[y] then begin
          reverse(x);
          x:=fa[x,0];
        end
        else begin
          reverse(y);
          y:=fa[y,0];
        end;
    end;
    
    procedure into;
    var
      i,j,k,l,sumcol:longint;
    begin
      readln(n,sumcol,m);
      long:=trunc(exp(ln(n)*2/3));
      esum:=0;
      for i:=1 to sumcol do read(value[i]);
      for i:=1 to n do read(w[i]);
      for i:=1 to n-1 do begin
        readln(j,k);
        addedge(j,k);
        addedge(k,j);
      end;
      deep[1]:=1;
      time:=0;
      if dfs(1)>0 then begin
        inc(total);
        for i:=1 to top do
          block[p[i]]:=total;
      end;
      for i:=1 to n do begin
        read(col[i]);
        pre[i]:=col[i];
      end;
      tot1:=0;
      tot2:=0;
      for i:=1 to m do begin
        read(j);
        if j=0 then begin
          inc(tot1);
          readln(j,k);
          ask1[tot1].pl:=j;
          ask1[tot1].new:=k;
          ask1[tot1].old:=pre[j];
          pre[j]:=k;
        end
        else begin
          inc(tot2);
          readln(j,k);
          if j>k then swap(j,k);
          ask2[tot2].u:=j;
          ask2[tot2].v:=k;
          ask2[tot2].pl:=tot2;
          ask2[tot2].t:=tot1;
        end;
      end;
      qsort(1,tot2);
    end;
    
    procedure work;
    var
      lastu,lastv,lastime,i,j,k:longint;
    begin
      lastu:=1;
      lastv:=1;
      lastime:=0;
      sum:=0;
      for i:=1 to tot2 do begin
        for j:=lastime+1 to ask2[i].t do change(ask1[j].pl,ask1[j].new);
        for j:=lastime downto ask2[i].t+1 do change(ask1[j].pl,ask1[j].old);
        solve(lastu,ask2[i].u);
        solve(lastv,ask2[i].v);
        k:=lca(ask2[i].u,ask2[i].v);
        lastu:=ask2[i].u;
        lastv:=ask2[i].v;
        lastime:=ask2[i].t;
       // writeln(ask2[i].pl,' ',lastu,' ',lastv,' ',lastime,' ',k,' ',sum);
      //  writeln;
        reverse(k);
        ans[ask2[i].pl]:=sum;
        reverse(k);
      end;
      for i:=1 to tot2 do
        writeln(ans[i]);
    end;
    
    begin
      into;
      work;
      readln;
      readln;
    end.
    View Code
  • 相关阅读:
    小程序开发-7-访问api数据与ES6在小程序中的应用
    小程序开发-8-流行页面编码与组件的细节知识
    小程序开发-6-组件数据、事件与属性
    当安装mongodb客户端出现了Failed to load list of databases
    对bluebird的理解
    百度地图实现案例
    iScroll实现下拉刷新上拉加载
    nodejs环境变量配置
    检测Python程序本身是否已经在运行
    用Python快速找到出现次数最多的数据
  • 原文地址:https://www.cnblogs.com/Macaulish/p/4282576.html
Copyright © 2011-2022 走看看