zoukankan      html  css  js  c++  java
  • Luogu P4137 Rmq Problem/mex

    这题可以用莫队做~

    先套一波莫队模板,然后我们可以用时间复杂度有时O(n)有时O(1)的的转移操作把这题卡过去qwq……

    先复习一遍莫队模板:莫队模板戳这里qwq

    我们看到数据范围:$0 leq a_i leq 10^9$,很显然我们这个数据不能直接开个数组来统计每个数出现的次数,但我们也知道,取$mex$时有很多数据是没有用的,比如那些大于$n$的数,这些数并不会影响我们的结果,所以我们可以直接排除掉他们。所以计数器数组只需开到$n$就可以了。

    然后就是莫队模板啦~

    var n,m,i,j,k,x,y,ans:longint;
    a,b,l,r,num,an:array[0..200000]of longint;
    function check(x1,y1,x2,y2:longint):boolean;
    begin
      if (trunc(x1/sqrt(n))>trunc(y1/sqrt(n)))or(trunc(x1/sqrt(n))=trunc(y1/sqrt(n)))and(x2>y2) then
      exit(true)
      else
      exit(false);
    end;
    procedure sort(ll,rr:longint);
    var i,j,x,y,z:longint;
    begin
      i:=ll;
      j:=rr;
      x:=l[(ll+rr) div 2];
      z:=r[(ll+rr) div 2];
      repeat
      while check(l[i],x,r[i],z) do
      inc(i);
      while check(x,l[j],z,r[j]) do
      dec(j);
      if not(i>j) then
      begin
        y:=l[i];
        l[i]:=l[j];
        l[j]:=y;
        y:=r[i];
        r[i]:=r[j];
        r[j]:=y;
        y:=num[i];
        num[i]:=num[j];
        num[j]:=y;
        inc(i);
        dec(j);
      end;
      until i>j;
      if ll<j then
      sort(ll,j);
      if i<rr then
      sort(i,rr);
    end;
    begin
      readln(n,m);
      for i:=1 to n do
      read(a[i]);
      for i:=1 to m do
      begin
        readln(l[i],r[i]);
        num[i]:=i;
      end;
      sort(1,m);
      for i:=l[1] to r[1] do
      if a[i]<=n then//排除大于n的值
      inc(b[a[i]]);
      for i:=0 to n do
      if b[i]=0 then
      begin
        an[num[1]]:=i;//num:答案编号;an:答案
        ans:=i;//ans记录当前最先找到的没有出现过的自然数
        break;
      end;
      x:=l[1];
      y:=r[1];
      for i:=2 to m do
      begin
        while x>l[i] do//左端点向左扩张
        begin
          dec(x);
          if a[x]>n then//值大于n就跳过
          continue;
          inc(b[a[x]]);
          if a[x]=ans then//如果当前扩张到的值就是最小值
          for j:=ans+1 to n do//继续往后搜最小值
          if b[j]=0 then
          begin
            ans:=j;
            break;
          end;
        end;
        while y<r[i] do//右端点向右扩张
        begin
          inc(y);
          if a[y]>n then//值大于n就跳过
          continue;
          inc(b[a[y]]);
          if a[y]=ans then//如果当前扩张到的值就是最小值
          for j:=ans+1 to n do//继续往后搜最小值
          if b[j]=0 then
          begin
            ans:=j;
            break;
          end;
        end;
        while x<l[i] do//左端点向右收缩
        begin
          if a[x]>n then//值大于n就跳过
          begin
            inc(x);
            continue;
          end;
          dec(b[a[x]]);
          if (b[a[x]]=0)and(a[x]<ans) then//如果当前收缩的值剩余个数为0且为最小值
          ans:=a[x];//记为最小值
          inc(x);
        end;
        while y>r[i] do//右端点向左收缩
        begin
          if a[y]>n then//值大于n就跳过
          begin
            dec(y);
            continue;
          end;
          dec(b[a[y]]);
          if (b[a[y]]=0)and(a[y]<ans) then//如果当前收缩的值剩余个数为0且为最小值
          ans:=a[y];//记为最小值
          dec(y);
        end;
        an[num[i]]:=ans;
      end;
      for i:=1 to m do
      writeln(an[i]);
    end.
  • 相关阅读:
    UVA 10600 ACM Contest and Blackout(次小生成树)
    UVA 10369
    UVA Live 6437 Power Plant 最小生成树
    UVA 1151 Buy or Build MST(最小生成树)
    UVA 1395 Slim Span 最小生成树
    POJ 1679 The Unique MST 次小生成树
    POJ 1789 Truck History 最小生成树
    POJ 1258 Agri-Net 最小生成树
    ubuntu 用法
    ubuntu 搭建ftp服务器,可以通过浏览器访问,filezilla上传文件等功能
  • 原文地址:https://www.cnblogs.com/qbwhtc/p/8413383.html
Copyright © 2011-2022 走看看