P11160 【MX-X6-T6】機械生命体
题面:
题目背景
許してよ、もう$\$
分かってよ$\$
此処の正体を$\$
僕ですら僕を$\$
愛せないんだって$\$
感情を持った代償をくれよ$\$
狂っている二进制的运算和记忆,能够在机械生命体中还原出人类的情感吗?
题目描述
维护一个可重集 S S S,初始为空。支持如下操作:
1 x
,你需要在 S S S 中加入一个数 x x x。2 x
,你需要在 S S S 中删除一个数 x x x。保证此时 S S S 中存在至少一个 x x x。如果存在多个 x x x,则仅删除一个。3 x k v
,你需要对 S S S 中所有满足 lowbit ( x ⊕ y ) ≥ 2 k \operatorname{lowbit}(x\oplus y)\geq 2^k lowbit(x⊕y)≥2k 的 y y y 增加 v v v 并对 2 32 2^{32} 232 取模。4 x
,你需要求出 max y ∈ S lowbit ( x ⊕ y ) \max\limits_{y\in S} \operatorname{lowbit}(x\oplus y) y∈Smaxlowbit(x⊕y)。保证此时 S S S 不为空。其中 lowbit ( x ) \operatorname{lowbit}(x) lowbit(x) 表示最大的整数 k k k,使得 k k k 是 2 2 2 的整数次幂并且整除 x x x。 ⊕ \oplus ⊕ 代表按位异或。
特殊的,我们在本题定义 lowbit ( 0 ) = 2 32 \boldsymbol{\textbf{lowbit}(0)=2^{32}} lowbit(0)=232。
输入格式
第一行一个整数 q q q,代表询问数量。
接下来 q q q 行,每行首先输入一个整数 o p t opt opt 表示操作类型;如果 o p t = 3 opt=3 opt=3,则接下来依次输入三个整数 x , k , v x,k,v x,k,v,否则接下来输入一个整数 x x x。
输出格式
对每一次
4
操作,输出一个整数代表答案。样例 #1
样例输入 #1
11 1 1 1 2 1 2 1 3 1 4 4 10 3 2 1 2 2 4 4 16 2 4 4 16
样例输出 #1
8 4 2
提示
【样例解释】
第 6 6 6 次操作时,集合为 { 1 , 2 , 2 , 3 , 4 } \{1,2,2,3,4\} {1,2,2,3,4},查询 10 10 10 时, lowbit ( 10 ⊕ 2 ) = lowbit ( 8 ) = 8 \operatorname{lowbit}(10\oplus 2)=\operatorname{lowbit}(8)=8 lowbit(10⊕2)=lowbit(8)=8 为最大值。
第 7 7 7 次操作后,所有 lowbit ( x ⊕ 2 ) ≥ 2 1 \operatorname{lowbit}(x\oplus 2)\geq 2^1 lowbit(x⊕2)≥21 的数增加 2 2 2,集合中满足条件的数有 2 , 2 , 4 2,2,4 2,2,4,于是集合变为 { 1 , 3 , 4 , 4 , 6 } \{1,3,4,4,6\} {1,3,4,4,6}。
第 8 8 8 次操作删去一个 4 4 4,集合变为 { 1 , 3 , 4 , 6 } \{1,3,4,6\} {1,3,4,6}。
第 9 9 9 次操作查询 16 16 16, lowbit ( 16 ⊕ 4 ) = lowbit ( 20 ) = 4 \operatorname{lowbit}(16\oplus 4)=\operatorname{lowbit}(20)=4 lowbit(16⊕4)=lowbit(20)=4 为最大值。
第 10 10 10 次操作再次删去一个 4 4 4,集合变为 { 1 , 3 , 6 } \{1,3,6\} {1,3,6}。
第 11 11 11 次操作查询 16 16 16, lowbit ( 16 ⊕ 6 ) = lowbit ( 22 ) = 2 \operatorname{lowbit}(16\oplus 6)=\operatorname{lowbit}(22)=2 lowbit(16⊕6)=lowbit(22)=2 为最大值。
【数据范围】
对于所有数据, 1 ≤ q ≤ 5 × 1 0 5 1\leq q\leq 5\times 10^5 1≤q≤5×105, 0 ≤ x , y , v ≤ 2 32 − 1 0\leq x,y,v\leq 2^{32}-1 0≤x,y,v≤232−1, 0 ≤ k ≤ 32 0\leq k\leq 32 0≤k≤32。
捆绑测试,共 5 个 Subtask,具体限制如下所示:
- Subtask 1(7 pts): q ≤ 1 0 3 q\leq 10^3 q≤103。
- Subtask 2(16 pts):不存在 3 操作。
- Subtask 3(21 pts):对于 3 操作, k = 0 k=0 k=0。
- Subtask 4(28 pts):对于 3 操作, v = 1 v=1 v=1。
- Subtask 5(28 pts):无特殊限制。
01-trie 的合并 → \rightarrow → 整体加 1 1 1 写过了,就得写一写 01-trie 的分裂与合并 → \rightarrow → 整体加 v v v
考虑将需要整体加的部分用 01trie 分裂,裂出来,整体加 tag \text{tag} tag
在 y y y 上 继承符合要求的 x x x 的子树,然后整体打 tag \text{tag} tag,放回去。
询问的时候,如果没有能匹配上 x x x 的 y ∈ S y \in S y∈S,就返回当前的 d e p dep dep
讲起来很简单,实现难的一批
AC-code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 5e5+5;
namespace sgt{
int ls[N * 30],rs[N * 30];
int s[N * 30],cnt,tag[N * 30];
void push_up(int p) {s[p] = s[ls[p]] + s[rs[p]];}
void addtag(int p,int v) {tag[p] += v;}
void push_down(int p) {
if(tag[p]) {
if(ls[p]) addtag(ls[p],tag[p] >> 1);
if(rs[p]) addtag(rs[p],(tag[p] + 1) >> 1);
if(tag[p] & 1) swap(ls[p],rs[p]);
tag[p] = 0;
}
}
void insert(int &p,int x,int v,int dep) {
if(!p) p = ++cnt;
if(dep >= 32) {s[p] += v;return;}
push_down(p);
(x >> dep) & 1 ? insert(rs[p],x,v,dep + 1) : insert(ls[p],x,v,dep + 1);
push_up(p);
}
#define t(p,x) (x ? rs[p] : ls[p])
int merge(int x,int y,int dep) {
if(!x || !y) return x + y;
if(dep >= 32) {
s[x] += s[y];
return x;
}
push_down(x);push_down(y);
ls[x] = merge(ls[x],ls[y],dep + 1);
rs[x] = merge(rs[x],rs[y],dep + 1);
push_up(x);
return x;
}
void spilt(int p,int y,int fa,int x,int k,int v,int dep) {
if(dep == k) {
tag[p] += v;
if(p ^ y) {
merge(y,p,dep);
if(ls[fa] == p) ls[fa] = 0;
else rs[fa] = 0;
}
return;
}
push_down(p);push_down(y);
int _x = x & 1,_dx;
v += _x;_dx = v & 1;
if(!t(p,_x)) t(p,_x) = ++cnt;
if(!t(y,_dx)) t(y,_dx) = ++cnt;
spilt(t(p,_x),t(y,_dx),p,x >> 1,k,v >> 1,dep + 1);
push_up(y);push_up(p);
}
void add(int &rt,int x,int k,int v) {spilt(rt,1,0,x,k,v,0);}
int query(int &p,int x,int dep) {
if(!p) {p = ++cnt;}
if(dep >= 32) return dep;
push_down(p);
if((x >> dep) & 1) {
if(s[rs[p]]) return query(rs[p],x,dep + 1);
else return dep;
}else {
if(s[ls[p]]) return query(ls[p],x,dep + 1);
else return dep;
}
}
}
int rt;
void ins() {
int x = rd();
sgt::insert(rt,x,1,0);
}
void del() {
int x = rd();
sgt::insert(rt,x,-1,0);
}
void change() {
int x = rd(),k = rd(),v = rd();
sgt::add(rt,x,k,v);
}
void get() {
int x = rd();
int ans = (sgt::query(rt,x,0));
wt(1LL << ans);
putchar('\n');
}
signed main() {
int q = rd();
while(q--) {
int opt = rd();
switch(opt) {
case 1:
ins();
break;
case 2:
del();
break;
case 3:
change();
break;
case 4:
get();
break;
default:
puts("Error");
exit(0);
break;
}
}
return 0;
}