0w1

HE XOR queries ( Persistent Segment Tree on BIT, XOR, Online, Kth )

XOR queries | Segment Trees & Data Structures Practice Problems | HackerEarth

題意:
給一個數列 A。要求在線處理 Q 筆詢問:
第一種:
__將 A[ i ] 改為 x
第二種:
__問 A[ l, r ] 排序後,其中 [ i, j ] 間的 xor 值為何。

制約:
N, Q ≤ 5e4
1 ≤ A[ i ], x ≤ 1e5

解法:
BIT 套持久化線段樹。首先想像維護第 i 棵線段樹保有區間中數值為 i 的數量。對第二種詢問,可以在 BIT 上二分搜出第 K 大的值為何,並用前綴和的關係就能處理答案 ( query( l, r, i, j ) = prefix_xor( l, r, i - 1 ) xor prefix_xor( l, r, j ) )。

時間 / 空間複雜度:
O( N lg^2 N + Q lg^2 N )

#include <bits/stdc++.h>
using namespace std;
 
const int MAXN = int( 5e4 );
const int MAXA = int( 1e5 );
 
int N, Q;
int A[ MAXN ];
 
tuple< int, int, int, int > online( int ans, int L, int R, int I, int J ) {
  int ll = 1 + ( ( ans ^ L ) % N );
  int rr = 1 + ( ( ans ^ R ) % N );
  if( ll > rr ) swap( ll, rr );
  int ii = 1 + ( ( I ^ ans ) % ( rr - ll + 1 ) );
  int jj = 1 + ( ( J ^ ans ) % ( rr - ll + 1 ) );
  if( ii > jj ) swap( ii, jj );
  return make_tuple( ll, rr, ii, jj );
}
 
struct pst { // persistent segment tree
  int cnt, xsum;
  pst *lc, *rc;
  pst() {
    cnt = xsum = 0;
    lc = rc = NULL;
  }
  void pull() {
    cnt = xsum = 0;
    if( lc ) {
      cnt += lc->cnt;
      xsum ^= lc->xsum;
    }
    if( rc ) {
      cnt += rc->cnt;
      xsum ^= rc->xsum;
    }
  }
} *root[ MAXA + 1 ];
 
pst* clone( pst *rt ) {
  pst *res = new pst();
  if( rt == NULL ) return res;
  res->cnt = rt->cnt;
  res->xsum = rt->xsum;
  res->lc = rt->lc;
  res->rc = rt->rc;
  return res;
}
 
pst* add( pst *rt, int lb, int rb, int k, int v, int x ) {
  pst *res = clone( rt );
  if( lb + 1 == rb ) {
    res->cnt += v;
    res->xsum ^= x;
    return res;
  }
  int mid = lb + rb >> 1;
  if( k < mid ) {
    res->lc = add( rt ? rt->lc : NULL, lb, mid, k, v, x );
  } else {
    res->rc = add( rt ? rt->rc : NULL, mid, rb, k, v, x );
  }
  res->pull();
  return res;
}
 
pair< int, int > query( pst *rt, int lb, int rb, int ql, int qr ) {
  if( rt == NULL or qr <= lb or rb <= ql ) return make_pair( 0, 0 );
  if( ql <= lb and rb <= qr ) return make_pair( rt->cnt, rt->xsum );
  int mid = lb + rb >> 1;
  pair< int, int > res( 0, 0 );
  if( rt->lc ) {
    int f, s;
    tie( f, s ) = query( rt->lc, lb, mid, ql, qr );
    res.first += f;
    res.second ^= s;
  }
  if( rt->rc ) {
    int f, s;
    tie( f, s ) = query( rt->rc, mid, rb, ql, qr );
    res.first += f;
    res.second ^= s;
  }
  return res;
}
 
int xsum_prefix_k( int k, int lb, int rb ) { // k: 1 base, [ lb, rb ): 0 base
  int x = 0;
  int res = 0;
  for( int i = 1 << 31 - __builtin_clz( MAXA ); i and k; i >>= 1 ) {
    if( x + i > MAXA ) continue;
    int cnt, xsum;
    tie( cnt, xsum ) = query( root[ x + i ], 0, N, lb, rb );
    if( cnt <= k ) {
      k -= cnt;
      res ^= xsum;
      x += i;
    }
  }
  return res;
}
 
signed main() {
  ios::sync_with_stdio( 0 );
  cin >> N >> Q;
  for( int i = 0; i < N; ++i ) {
    cin >> A[ i ];
    for( int j = A[ i ]; j <= MAXA; j += j & -j ) {
      root[ j ] = add( root[ j ], 0, N, i, 1, A[ i ] );
    }
  }
  int ans = 0;
  for( int qi = 0; qi < Q; ++qi ) {
    int op;
    cin >> op;
    if( op == 1 ) {
      int id, x;
      cin >> id >> x;
      for( int i = A[ id - 1 ]; i <= MAXA; i += i & -i ) {
        root[ i ] = add( root[ i ], 0, N, id - 1, -1, A[ id - 1 ] );
      }
      A[ id - 1 ] = x;
      for( int i = A[ id - 1 ]; i <= MAXA; i += i & -i ) {
        root[ i ] = add( root[ i ], 0, N, id - 1, 1, A[ id - 1 ] );
      }
    } else {
      int L, R, I, J;
      cin >> L >> R >> I >> J;
      int ll, rr, ii, jj;
      tie( ll, rr, ii, jj ) = online( ans, L, R, I, J );
      ans = xsum_prefix_k( ii - 1, ll - 1, rr ) ^ xsum_prefix_k( jj, ll - 1, rr );
      cout << ans << "\n";
    }
  }
  return 0;
}