BZOJ4103 [Thu Summer Camp 2015]异或运算 【可持久化trie树】

题目链接

BZOJ4103

题解

一眼看过去是二维结构,实则未然需要树套树之类的数据结构
区域异或和,就一定是可持久化\(trie\)

观察数据,\(m\)非常大,而\(n\)\(p\)比较小,甚至可以每次询问都枚举\(x_i\)
所以我们可以考虑对\(y_i\)\(trie\),每次询问取出对应区间的\(x_i\)在对应区间的\(trie\)树中跑

多点询问和单点询问时类似的,只不过它们会分开走
我们只需每次记录每个\(x_i\)所在的节点
对于每一层,统计一下能异或出多少\(1\),如果\(\le k\),每个\(x_i\)往能异或出\(1\)的方向走,否则走另一边,并令\(k\)减去这些数

复杂度\(O(31m + 31qn)\)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 300005,B = 30,maxm = 10000005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int bin[50],n,m;
int a[1005],b[maxn],rt[maxn],cnt;
int ch[maxm][2],sum[maxm];
int ins(int x,int v){
    int u,tmp;
    u = tmp = ++cnt;
    for (int i = B; ~i; i--){
        ch[u][0] = ch[v][0];
        ch[u][1] = ch[v][1];
        sum[u] = sum[v] + 1;
        int t = bin[i] & x; t >>= i;
        v = ch[v][t];
        u = ch[u][t] = ++cnt;
    }
    sum[u] = sum[v] + 1;
    return tmp;
}
int atu[1005],atv[1005];
int query(int u,int v,int l,int r,int k){
    int ans = 0;
    for (int i = l; i <= r; i++) atu[i] = u,atv[i] = v;
    for (int i = B; ~i; i--){
        int cnt = 0;
        for (int j = l; j <= r; j++){
            int x = atu[j],y = atv[j],t = bin[i] & a[j]; t >>= i;
            cnt += sum[ch[x][t ^ 1]] - sum[ch[y][t ^ 1]];
        }
        if (cnt >= k){
            ans += bin[i];
            for (int j = l; j <= r; j++){
                int x = atu[j],y = atv[j],t = bin[i] & a[j]; t >>= i;
                atu[j] = ch[x][t ^ 1];
                atv[j] = ch[y][t ^ 1];
            }           
        }
        else {
            k -= cnt;
            for (int j = l; j <= r; j++){
                int x = atu[j],y = atv[j],t = bin[i] & a[j]; t >>= i;
                atu[j] = ch[x][t];
                atv[j] = ch[y][t];
            }
        }
    }
    return ans;
}
int main(){
    bin[0] = 1; for (int i = 1; i <= 30; i++) bin[i] = bin[i - 1] << 1;
    n = read(); m = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i <= m; i++){
        b[i] = read();
        rt[i] = ins(b[i],rt[i - 1]);
    }
    int p = read(),u,d,l,r,k;
    while (p--){
        u = read(); d = read(); l = read(); r = read(); k = read();
        printf("%d\n",query(rt[r],rt[l - 1],u,d,k));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mychael/p/9084889.html