P11160 【MX-X6-T6】機械生命体 题解

P11160 【MX-X6-T6】機械生命体

题面:

题目背景

許してよ、もう$\$
分かってよ$\$
此処の正体を$\$
僕ですら僕を$\$
愛せないんだって$\$
感情を持った代償をくれよ$\$
狂っている

—— 機械生命体 - Nanatsukaze

二进制的运算和记忆,能够在机械生命体中还原出人类的情感吗?

题目描述

维护一个可重集 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(xy)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) ySmaxlowbit(xy)。保证此时 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(102)=lowbit(8)=8 为最大值。

7 7 7 次操作后,所有 lowbit ⁡ ( x ⊕ 2 ) ≥ 2 1 \operatorname{lowbit}(x\oplus 2)\geq 2^1 lowbit(x2)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(164)=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(166)=lowbit(22)=2 为最大值。

【数据范围】

对于所有数据, 1 ≤ q ≤ 5 × 1 0 5 1\leq q\leq 5\times 10^5 1q5×105 0 ≤ x , y , v ≤ 2 32 − 1 0\leq x,y,v\leq 2^{32}-1 0x,y,v2321 0 ≤ k ≤ 32 0\leq k\leq 32 0k32

捆绑测试,共 5 个 Subtask,具体限制如下所示:

  • Subtask 1(7 pts): q ≤ 1 0 3 q\leq 10^3 q103
  • 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 yS,就返回当前的 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值