维护一个集合,初始时集合为空,支持如下几种操作: I x,插入一个数 x; PM,输出当前集合中的最小值; DM,删除当前集合中的最小值(数据保证此时的最小值唯一); D k,删除第 k 个插入的数; C k x,修改第 k 个插入的数,将其变为 x; 现在要进行 N 次操作,对于所有第 2 个操作,输出当前集合的最小值。
输入格式 第一行包含整数 N。 接下来 N 行,每行包含一个操作指令,操作指令为 I x,PM,DM,D k 或 C k x 中的一种。
输出格式 对于每个输出指令 PM,输出一个结果,表示当前集合中的最小值。 每个结果占一行。
数据范围 1≤N≤10^5 −10^9≤x≤10^9 数据保证合法。
输入样例: 8 I -10 PM I -10 D 1 C 28 I 6 PM DM 输出样例: -10 6
#include<iostream> #include<algorithm> usingnamespacestd; #define IOS \ ios::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0) constint N = 1e5+ 5; int n,a; int son[N*31][2],idx;
voidinsert(int a){// 插入a的二进制形式 int p = 0; for (int i = 30;i >= 0;i --){// a的二进制形式有31位 int u = a >> i & 1;// 取出a的二进制形式的第i位数字(0 <= i <= 30) if (!son[p][u]) son[p][u] = ++idx; p = son[p][u];// 走到子节点 } }
intquery(int a){// 贪心查找Trie树中与a异或最大的数 int p = 0,res = 0; for (int i = 30;i >= 0;i --){ int u = a >> i & 1; if (son[p][!u]){ p = son[p][!u];// 如果存在与u相反的数,走这条路 res = res * 2 + !u;// 将二进制形式转换为十进制 } else{ p = son[p][u];// 没有的话只能走相同的路 res = res * 2 + u; } } return res; }
intmain(){ IOS; int res = 0; cin >> n; while (n--){ cin >> a; insert(a);// 先插入再查询 res = max(res,a ^ query(a)); } cout << res << '\n'; return0; }
// 写法2: // xxx if (son[p][!u]){ p = son[p][!u];// 如果存在与u相反的数,走这条路 res = res * 2 + 1;// 将二进制形式转换为十进制 } else{ p = son[p][u];// 没有的话只能走相同的路 res = res * 2 + 0; } // xxx res = max(res,query(a));
动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。 A 吃 B,B 吃 C,C 吃 A。 现有 N 个动物,以 1∼N 编号。 每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。 有人用两种说法对这 N 个动物所构成的食物链关系进行描述: 第一种说法是 1 X Y,表示 X 和 Y 是同类。 第二种说法是 2 X Y,表示 X 吃 Y。 此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。 当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 当前的话与前面的某些真的话冲突,就是假话; 当前的话中 X 或 Y 比 N 大,就是假话; 当前的话表示 X 吃 X,就是假话。 你的任务是根据给定的 N 和 K 句话,输出假话的总数。
输入格式 第一行是两个整数 N 和 K,以一个空格分隔。 以下 K 行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中 D 表示说法的种类。 若 D=1,则表示 X 和 Y 是同类。 若 D=2,则表示 X 吃 Y。