经典题,\(\rm 01Trie\) 和 主席树的结合。
考虑一个没有偏移量的时候如何计算,其实就是一个裸的可持久化 \(\rm Trie\)。
但是有了偏移量就不一样了,这会导致直接改变 \(\rm Trie\) 的结构,十分不好做。
套路的逐位考虑,从高位枚举到低位。假设当前找到的数为 \(\rm ret\),考虑到 \(i\) 位,则不难发现可以选择的值域区间为 \([ret - add, ret + 2 ^ {i + 1} - add]\)。其中前 \(2^i\) 个数 \(i\) 位为 \(0\) , 剩余为 \(1\).
由 \(\rm 01Trie\) 的思想,我们尽量往反向走,那么我们只需要查找反向区间中是否有数字,使用主席树即可。
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10, M = 1e5;
struct Persist_Seg{
#define mid (l + r >> 1)
struct node{
int ls, rs, sum;
}hjt[N << 5];
int root[N], cnt;
void pushup(int o){hjt[o].sum = hjt[hjt[o].ls].sum + hjt[hjt[o].rs].sum;}
void add(int l, int r, int pre, int& now, int x){
hjt[++cnt] = hjt[pre]; now = cnt;
if(l == r){hjt[now].sum++; return;}
if(x <= mid) add(l, mid, hjt[pre].ls, hjt[now].ls, x);
else add(mid + 1, r, hjt[pre].rs, hjt[now].rs, x);
pushup(now);
}
bool check(int l, int r, int Lo, int Ro, int s, int t){
if(l > r) return false;
if(s <= l && r <= t) return hjt[Ro].sum - hjt[Lo].sum;
bool ret = false;
if(s <= mid) ret |= check(l, mid, hjt[Lo].ls, hjt[Ro].ls, s, t);
if(mid < t) ret |= check(mid + 1, r, hjt[Lo].rs, hjt[Ro].rs, s, t);
return ret;
}
}tr;
int n, m;
int solve(int pivot, int ad, int l, int r){
int ret = 0;
for(int i = 20; i >= 0; i--){
int c = pivot & (1 << i);
if(c && !tr.check(0, M, tr.root[l - 1], tr.root[r], ret - ad, ret - ad + (1 << i) - 1)) ret += (1 << i);
else if(!c && tr.check(0, M, tr.root[l - 1], tr.root[r], ret - ad + (1 << i), ret - ad + (1 << i + 1) - 1)) ret += (1 << i);
}
return ret ^ pivot;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++){
int x; cin >> x;
tr.add(0, M, tr.root[i - 1], tr.root[i], x);
}
for(int i = 1; i <= m; i++){
int b, x, l, r;
cin >> b >> x >> l >> r;
cout << solve(b, x, l, r) << "\n";
}
return 0;
}
标签:struct,int,tr,P3293,add,ret,rm,SCOI2016,美味
From: https://www.cnblogs.com/little-corn/p/18157527