1. 程式人生 > 其它 >UOJ681【UR #22】月球列車【二進位制,Trie】

UOJ681【UR #22】月球列車【二進位制,Trie】

給定 \(n\) 個自然數 \(a_1,\cdots,a_n\)\(m\) 次詢問自然數 \(v\),求 \(\bigoplus_{i=1}^n(a_i+x)\) 的值。

\(n,m\le 2.5\cdot 10^5\)\(0\le a_i,x<2^{60}\),強制線上。


考慮暴力,設現在要求答案的第 \(j\) 位,而 \(a_i+v\) 的第 \(j\) 位即為 \(a_i\oplus v\) 的第 \(j\) 位異或上 \(a_i+v\) 的第 \(j-1\) 位是否進位,設 \(a'_{j,i}=a_i\&(2^{j+1}-1)\),後者也即 \(a'_{j-1,i}\ge 2^j-(v\&(2^j-1))\)

,對 \(a'_{j,i}\) 排序後二分即可,時間複雜度 \(O((n+m)\log n\log V)\)

而排序預處理的部分可以利用上一次排序的結果:設對 \(j\) 預處理出的 \(a'_{j,i}\) 排序後的結果為 \(b_{j,1}\le\cdots\le b_{j,n}\),直接將 \(b_{j-1,i}\) 中第 \(j\) 位為 \(0,1\) 的分離即得 \(b_{j,i}\)

考慮對二分過程也類似處理。預處理 \(s_{0/1,j,i}\) 表示 \(b_{j-1,1},\cdots,b_{j-1,i}\) 中有多少個第 \(j\) 位為 \(0/1\) 的,查詢時從小到大列舉 \(j\)

,維護 \(x\) 表示滿足上述不等式(第 \(j\) 位進位)的 \(i\) 的個數。

  • \(v\) 的第 \(j\) 位為 \(1\),則後 \(j\) 位進位時貢獻為 \(s_{1,j,n}-s_{1,j,n-x}\),不進位時貢獻為 \(s_{0,j,n-x}\),然後令 \(x:=n-s_{0,j,n-x}\)
  • \(v\) 的第 \(j\) 位為 \(0\),則後 \(j\) 位進位時貢獻為 \(s_{0,j,n}-s_{0,j,n-x}\),不進位時貢獻為 \(s_{1,j,n-x}\),然後令 \(x:=s_{1,j,n}-s_{1,j,n-x}\)

時間複雜度 \(O((n+m)\log V)\)

,空間複雜度 \(O(n\log V)\)

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long LL;
const int N = 250003;
int n, m, op, p[N], t[2][N], s[61][N];
LL a[N], v, ans;
int main(){
    ios::sync_with_stdio(false);
    cin >> n >> m >> op;
    for(int i = 1;i <= n;++ i){cin >> a[i]; p[i] = i;}
    for(int i = 0;i < 61;++ i){
        t[0][0] = t[1][0] = 0;
        for(int j = 1;j <= n;++ j){
            bool x = a[p[j]]>>i&1;
            t[x][++t[x][0]] = p[j];
            s[i][j] = t[0][0];
        }
        for(int i = 1;i <= t[0][0];++ i) p[i] = t[0][i];
        for(int i = 1;i <= t[1][0];++ i) p[i+t[0][0]] = t[1][i];
    }
    while(m --){
        cin >> v; if(op) v ^= ans >> 20;
        int x = 0; ans = 0;
        for(int i = 0;i < 61;++ i)
            if(v >> i & 1){
                ans |= ((x ^ s[i][n]) & 1ll) << i;
                x = n - s[i][n-x];
            } else {
                ans |= ((n ^ x ^ s[i][n]) & 1ll) << i;
                x += s[i][n-x] - s[i][n];
            }
        printf("%llu\n", ans);
    }
}