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.
  • 相关阅读:
    intellij idea for mac 2018 破解版
    Mac下Supervisor进程监控管理工具的安装与配置
    Mysql千万级大表优化策略
    php7实现基于openssl的加密解密方法
    openresty--centos7下开发环境安装
    webstorm下搭建编译less环境 以及设置压缩css
    七牛图片上传
    聊一聊PHP的依赖注入(DI) 和 控制反转(IoC)
    joomla! 3.X 开发系列教程
    JSON反序列化接口的问题
  • 原文地址:https://www.cnblogs.com/qbwhtc/p/8413383.html
Copyright © 2011-2022 走看看