2 条题解

  • 4
    @ 2022-3-23 20:14:25

    题意:让你维护一个序列,支持区间询问第 KK 小,单点修改,在某个数前插入一个数。

    你发现这个数据范围很小,于是你可以随意地整一个 O(nnpolylog n)O(n\sqrt n\text{polylog } n) 的算法。

    于是还是传统艺能地块状链表,你先分块,分成 BB 块,然后插入就适当地自动分裂。

    然后你每个块都记录一个排序好的结果,动态维护这个东西。

    然后每次你询问一个区间的时候就二分判定一个数是否是第 KK 小。

    判定时就把散块的数处理掉,整块的东西再用二分掏出来即可。

    复杂度 O(nnlognlogV)O(n\sqrt n\log n\log V)VV 代表值域。

    #define maxn 70010
    #define B 1024
    int n,m;
    int a[B][B*2],b[B][B*2];
    int lst,l,r,x,k;
    char ch[2];
    int nxt[B];
    const int blo=512;
    int pos[maxn],L[B],R[B],tot,siz[B];
    int ask(int l,int r,int k){
      int p=1,q=1;
      while(siz[p]<l)l-=siz[p],p=nxt[p];
      while(siz[q]<r)r-=siz[q],q=nxt[q];
      int tl=0,tr=70000,mid;
      while(tl<=tr){
        mid=(tl+tr)>>1;
        int t=0;
        if(p==q)rep(i,l,r)t+=a[p][i]<mid;
        else{
          rep(i,l,siz[p])t+=a[p][i]<mid;
          rep(i,1,r)t+=a[q][i]<mid;
          int pos=nxt[p];
          while(pos!=q){
            t+=lower_bound(b[pos]+1,b[pos]+siz[pos]+1,mid)-b[pos]-1;
            pos=nxt[pos];
          }
        }
        if(t<k)tl=mid+1;
        else tr=mid-1;
      }
      return tr;
    }
    void change(int x,int y){
      int p=1,k;
      while(siz[p]<x)x-=siz[p],p=nxt[p];
      rep(i,1,siz[p])if(b[p][i]==a[p][x]){
        k=i;
        break;
      }
      b[p][k]=a[p][x]=y;
      while(k>1&&b[p][k]<b[p][k-1])swap(b[p][k],b[p][k-1]),k--;
      while(k<siz[p]&&b[p][k]>b[p][k+1])swap(b[p][k],b[p][k+1]),k++;
    }
    void make(int x){
      rep(i,1,siz[x])b[x][i]=a[x][i];
      sort(b[x]+1,b[x]+siz[x]+1);
    }
    void insert(int x,int y){
      x--;
      int p=1;
      while(siz[p]<x)x-=siz[p],p=nxt[p];
      per(i,siz[p],x+1)a[p][i+1]=a[p][i];
      siz[p]++;
      a[p][x+1]=y;
      b[p][siz[p]]=y;
      if(siz[p]==2*blo){
        nxt[++tot]=nxt[p];
        nxt[p]=tot;
        rep(i,1,blo)a[tot][i]=a[p][i+blo];
        siz[p]=siz[tot]=blo;
        make(p),make(tot);
      }else{
        int k=siz[p];
        while(k>1&&b[p][k]<b[p][k-1])swap(b[p][k],b[p][k-1]),k--;
      }
    }
    signed main(){
      cin>>n;
      tot=n>>9;
      if(n&511)tot++;
      rep(i,1,tot){
        L[i]=R[i-1]+1;
        R[i]=L[i]+blo-1;
      }R[tot]=n;
      rep(i,1,tot){
        siz[i]=R[i]-L[i]+1;
        rep(j,L[i],R[i])
        cin>>a[i][j-L[i]+1],pos[j]=i;
        if(i<tot)nxt[i]=i+1;
        make(i);
      }
      cin>>m;
      while(m--){
        cin>>ch;
        cin>>l>>r;l^=lst,r^=lst;
        if(ch[0]=='Q'){
          cin>>k,k^=lst;
          cout<<(lst=ask(l,r,k))<<endl;
        }
        if(ch[0]=='M')change(l,r);
        if(ch[0]=='I')insert(l,r);
      }
    }
    

    O(nnlognlogV)O(n\sqrt n\log n\log V) 跑得比 O(nlog2n)O(n\log^2n) 快/kk

    • 0
      @ 2024-2-14 19:36:19

      思路和别人差不多,lxl牛逼。主要得使劲卡。等哪天试试进1000ms。

      #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt")
      #include <iostream>
      #include <queue>
      #include <vector>
      #include <algorithm>
      #include <cstring>
      #include <cstdlib>
      #include <cassert>
      #include <cstdio>
      #include <map>
      #include <set>
      #define u32 unsigned
      using namespace std;
      #define il inline
      #define ri register
      #define getcha() (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 20, stdin), SS == TT) ? EOF : *SS++)
      #define isint(a) ((a >= '0') && (a <= '9'))
      #define isch(a) ((a >= 'A') && (a <= 'Z'))
      char BB[1 << 20], *SS = BB, *TT = BB;
      inline u32 read() {
          u32 s = 0;
          char ch = getcha();
      
          while (!isint(ch))
              ch = getcha();
      
          while (isint(ch))
              s = (s << 3) + (s << 1) + (ch ^ 48), ch = getcha();
      
          return s;
      }
      inline u32 rad() {
          char ch = getcha();
      
          while (!isch(ch))
              ch = getcha();
      
          return (ch == 'Q' ? 1 : (ch == 'M' ? 2 : 3));
      }
      const u32 siz = 600;
      const u32 zis = 1300;
      const u32 blo = 300;
      const u32 mxval = 70003;
      const u32 vsiz = 512;
      const u32 vblo = 303;
      struct ee {
          u32 len;
          u32 ab[zis + 30];
          u32 ba[mxval], baa[vblo];
          il void ins(u32 a) {
              ++ba[a], ++baa[a >> 9];
          }
          il void del(u32 a) {
              --ba[a], --baa[a >> 9];
          }
          il void insert(u32 x, u32 bb) {
              for (u32 i = len; i >= x; --i)
                  ab[i + 1] = ab[i];
      
              ++len, ab[x] = bb, ins(bb);
          }
      } a[blo], tm;
      struct mi {
          u32 aa, bb;
          mi(const u32 &_aa, const u32 &_bb) : aa(_aa), bb(_bb) {}
      };
      u32 pos[blo], lock;
      il mi getpos(u32 x) {
          for (u32 i = 1; i <= lock; ++i)
              if (x <= a[pos[i]].len)
                  return mi(i, x);
              else
                  x -= a[pos[i]].len;
      
          return mi(0, 0);
      }
      il void modi(u32 x, u32 bb) {
          for (u32 i = 1; i <= lock; ++i)
              if (x <= a[pos[i]].len) {
                  u32 k = a[pos[i]].ab[x];
                  a[pos[i]].ab[x] = bb;
      
                  for (u32 j = i; j <= lock; ++j)
                      a[pos[j]].ins(bb), a[pos[j]].del(k);
      
                  return;
              } else
                  x -= a[pos[i]].len;
      }
      il void split(u32 x) {
          if (a[pos[x]].len <= zis)
              return;
      
          ++lock;
          u32 eee = pos[x];
      
          for (u32 j = 0; j <= 70000; ++j)
              a[lock].ba[j] = a[eee].ba[j];
      
          for (u32 j = 0; j <= 140; ++j)
              a[lock].baa[j] = a[eee].baa[j];
      
          for (u32 i = siz + 1; i <= a[eee].len; ++i)
              a[lock].ab[i - siz] = a[eee].ab[i], a[eee].del(a[eee].ab[i]);
      
          a[lock].len = a[eee].len - siz, a[eee].len = siz;
      
          for (u32 i = lock; i > x + 1; --i)
              pos[i] = pos[i - 1];
      
          pos[x + 1] = lock;
      }
      il void insert(u32 x, u32 bb) {
          for (u32 i = 1, k; i <= lock; ++i)
              if (x <= a[pos[i]].len + 1) {
                  k = pos[i];
      
                  for (u32 i = a[k].len; i >= x; --i)
                      a[k].ab[i + 1] = a[k].ab[i];
      
                  ++a[k].len, a[k].ab[x] = bb, a[k].ins(bb);
      
                  // a[pos[i]].insert(x, bb);
                  for (u32 j = i + 1; j <= lock; ++j)
                      a[pos[j]].ins(bb);
      
                  split(i);
                  return;
              } else
                  x -= a[pos[i]].len;
      }
      u32 b[100005];
      char ab[700000];
      u32 wh, st[20], top;
      il void print(u32 x) {
          while (x >= 10)
              st[++top] = x % 10, x /= 10;
      
          st[++top] = x;
      
          while (top)
              ab[wh++] = st[top] + '0',
                         --top;
      
          ab[wh++] = '\n';
      }
      main() {
          u32 n = read();
      
          for (u32 i = 1; i <= n; ++i)
              ++a[i / siz].len, a[i / siz].ab[a[i / siz].len] = read(), a[i / siz].ins(a[i / siz].ab[a[i / siz].len]);
      
          lock = n / siz + 1;
      
          for (u32 i = 1; i <= lock; ++i)
              pos[i] = i - 1;
      
          for (u32 i = 1; i < lock; ++i) {
              for (u32 j = 0; j <= 70000; ++j)
                  a[i].ba[j] += a[i - 1].ba[j];
      
              for (u32 j = 0; j <= 140; ++j)
                  a[i].baa[j] += a[i - 1].baa[j];
          }
      
          u32 m = read();
      
          for (u32 i = 1, lastans = 0, opt, l, r, k; i <= m; ++i) {
              opt = rad();
              l = (read() ^ lastans), r = (read() ^ lastans);
      
              if (opt == 1) {
                  k = (read() ^ lastans);
                  lastans = 0;
                  mi a1 = getpos(l), a2 = getpos(r);
      
                  if (a1.aa == a2.aa) {
                      for (u32 j = a1.bb, kkk = a1.bb, tmp = a2.bb; j <= tmp; ++j)
                          b[j - kkk + l] = a[pos[a1.aa]].ab[j];
      
                      nth_element(b + l, b + l + k - 1, b + r + 1);
                      lastans = b[l + k - 1];
                  } else {
                      for (u32 j = a1.bb, tmp = a[pos[a1.aa]].len; j <= tmp; ++j)
                          tm.ins(a[pos[a1.aa]].ab[j]);
      
                      for (u32 j = a2.bb; j >= 1; --j)
                          tm.ins(a[pos[a2.aa]].ab[j]);
      
                      u32 res = -1;
      
                      for (u32 j = pos[a1.aa], tmp = pos[a2.aa - 1], aaa = 0, bbb; aaa <= 140; ++aaa) {
                          bbb = tm.baa[aaa] + a[tmp].baa[aaa] - a[j].baa[aaa];
      
                          if (k > tm.baa[aaa] + a[tmp].baa[aaa] - a[j].baa[aaa])
                              res += vsiz, k -= bbb;
                          else {
                              bbb = tm.ba[res + 1] + a[tmp].ba[res + 1] - a[j].ba[res + 1];
      
                              while (k > bbb)
                                  k -= bbb, ++res, bbb = tm.ba[res + 1] + a[tmp].ba[res + 1] - a[j].ba[res + 1];
      
                              ++res;
                              break;
                          }
                      }
      
                      for (u32 j = a1.bb, tmp = a[pos[a1.aa]].len; j <= tmp; ++j)
                          tm.del(a[pos[a1.aa]].ab[j]);
      
                      for (u32 j = a2.bb; j >= 1; --j)
                          tm.del(a[pos[a2.aa]].ab[j]);
      
                      lastans = res;
                  }
      
                  print(lastans);
              } else if (opt == 2)
                  modi(l, r);
              else
                  insert(l, r);
          }
      
          fwrite(ab, 1, wh, stdout);
          return 0;
      }
      
      • 1

      信息

      ID
      3065
      时间
      3000ms
      内存
      256MiB
      难度
      8
      标签
      (无)
      递交数
      142
      已通过
      26
      上传者