[Solution] P1903 [国家集训队]数颜色 / 维护队列

支持修改的莫队

题目地址


  • 对于每一个询问,记录以下内容:

    • \(\text{Left,Right}\):左右边界
    • \(\text{Mapping}\):时间轴,即在这个询问之前已经完成了前\(\text{Mapping}\)个修改
  • 按照\(\text{Left}\)为第一关键字,\(\text{Right}\)为第二关键字,\(\text{Mapping}\)为第三关键字对询问排序。

  • 莫队状态的转移:

    • 在相同时间里,和普通莫队没有差异。
    • 在不同时间里,如果询问的时间较早需要逐个消除操作的影响。如果询问的时间晚,需要逐个进行操作。
  • 常数优化

    • \(\text{main}\)函数里的局部变量要快于全局变量。
    • 使用读入/输出优化。
  • Code

    • /*     --- Hope in Hand ---     */
      #include <stdio.h>
      #include <string.h>
      #include <algorithm>
      #define GC getchar()
      #define Clean(X,K) memset(X,K,sizeof(X))
      int Qread () {
          int X = 0 ;
          char C = GC ;
          while (C > '9' || C < '0') C = GC ;
          while (C >='0' && C <='9') {
              X = X * 10 + C - '0' ;
              C = GC ;
          }
          return X ;
      }
      const int Maxn = 50005 , U = 1000005;
      int A[Maxn]  ,Ans[Maxn] , Vis[U];
      struct Node {
          int X , Y , TIME , Mapping , Place , Raw_Value;
      };
      Node Ask [Maxn] , Add[Maxn] ;
      bool Cmp (const Node &A , const Node &B) {
          if (A.X != B.X )return A.X < B.X ;
          if (A.Y != B.Y ) return (A.X &1 ? A.Y < B.Y : A.Y > B.Y ) ;
          return (A.Y & 1 ? A.TIME < B.TIME : A.TIME > B.TIME ) ;
      }
      void Write(int X) {
          if( X > 9 ) Write(X / 10);
          putchar(X % 10+ '0');
      }
      int main () {
          int L = 0 , R = 0 , Time = 0 , Now = 0 , N  ,M , Cq = 0 , Cr = 0 ;
          N = Qread () , M = Qread ();
          for (int i = 1 ; i <= N; ++ i) A[i] = Qread () ;
          for (int i = 1 ; i <= M; ++ i) {
              char C = GC ;
              while (C != 'Q' && C != 'R') C = GC ;
              if (C == 'Q') {
                  Ask[++ Cq].X = Qread () ;
                  Ask[Cq].Y = Qread () ;
                  Ask[Cq].TIME = i ;
                  Ask[Cq].Mapping = Cr ;
                  Ask[Cq].Place = Cq ;
              } else {
                  Add[++Cr].X = Qread () ;
                  Add[Cr].Y = Qread () ;
                  Add[Cr].TIME = i ;
                  Add[Cr].Mapping = Cq ;
              }
          }
          Clean (Vis , 0) ;
          L = R = 1 , Vis[A[L]] = 1 , Now = 1 ;
          std :: sort (Ask + 1 , Ask + 1 + Cq , Cmp) ;
          for (int i = 1 ; i <= Cq ; ++ i) {
              while (L < Ask[i].X ) {
                  -- Vis[A[L]] ;
                  if (!Vis[A[L]]) -- Now ;
                  ++ L ;
              }
        
              while (R < Ask[i].Y ) {
                  ++ R ;
                  ++ Vis[A[R]] ;
                  if (Vis[A[R]] == 1) ++ Now ;
              }
        
              while (R > Ask[i].Y ) {
                  -- Vis[A[R]] ;
                  if (!Vis[A[R]]) -- Now ;
                  -- R ;
              }
              while (Time < Ask[i].Mapping ) {
                  ++ Time ;
                  if (Add[Time].X >= L && Add[Time].X <= R) {
                      --Vis[A[Add[Time].X ]]  ;
                      if (Vis[A[Add[Time].X ]] == 0)  --Now ;
                      ++Vis[Add[Time].Y ]  ;
                      if (Vis[Add[Time].Y ]== 1) ++Now  ;
                  }
                  Add[Time].Raw_Value = A[Add[Time].X ] ;
                  A[Add[Time].X ] = Add[Time].Y ;
              }
              while (Time > Ask[i].Mapping ) {
                  if (Add[Time].X >= L && Add[Time].X <= R) {
                      Vis[Add[Time].Y ] -- ;
                      if (Vis[Add[Time].Y ] == 0) --Now  ;
                      ++Vis[Add[Time].Raw_Value  ]  ;
                      if (Vis[Add[Time].Raw_Value  ]== 1) ++Now  ;
                  }
                  A[Add[Time].X ] = Add[Time].Raw_Value ;
                  --Time ;
              }
              Ans[Ask[i].Place ] = Now ;
          }
        
          for (int i = 1 ; i  <= Cq; ++ i)Write (Ans[i]) , putchar(10);
          fclose (stdin) , fclose (stdout) ;
          return 0 ;
      }
      

Thanks!

posted @ 2019-05-14 14:48  Betulaceae  阅读(113)  评论(0编辑  收藏  举报