题目链接:Here
这一题是我今年省赛最大的遗憾啊。诶。。。想想就觉得伤心啊。这一题其实不难,但是比赛时,我已经先到了怎么做,但是由于鄙人的失误,结果导致我们队后两个小时的时间都耗在那里了。越想越觉得可惜啊。我们现在看看这题的思路吧。
这一题,貌似大多人都是有STL的set做的。其实,这一题可以用线段树做(不知道线段树的童鞋请移步:这里),而且还是简单的单点更新问题。不知道单点更新的同学请移步:这里。虽然我做线段树的题目不是很多,但是我发现了一个规律。利用这个规律就可以更好的判断,此题是否为线段树的题目。
规律:题目中一般有插入删除之类的操作,数据范围一般在10的5次方到10的6次方左右,这样的题目一般都可以用线段树来解(纯属个人经验,如有例外欢迎指出,不过我还没见过不服从这个规律的线段树的题目)。
现在我们言归正传。对于这一题我们应该怎么用线段树处理呢?我们利用结构体,定义两个变量value, cnt。value用来存储输入的值(如果没有输入,那么久给它一个很大的值),cnt用来记录该节点的值被输入的次数。如果输入次数为1的话,那么我们就让 value 的值等于叶子节点的值。这样题目就转化为一个单点更新,区间最值问题了。具体操作,详见代码。
这一题还有一个坑,不知道省赛是是不是这样。就是每一组操作后,它多给了一个空格例如:“b 2 ”这样。千万要注意,不然就是万年RE。
【代码如下】
//因为 log2(1000000)约为 20 //所以树的深度为20 #include <stdio.h> #define MAXN 1<<20 #define Max 1e+6 #define INF 0xfffffff #define min(a,b) a<b?a:b struct ST{ int value, cnt; }node[2*MAXN]; int father[MAXN]; void build(int v, int left, int right){ node[v].value = INF; node[v].cnt = 0; if (left == right){ father[left] = v; return; } int mid = (left + right) / 2; build(2 * v, left, mid); build(2 * v + 1, mid + 1, right); return; } void Update(int ri){ if (ri == 1) return; int fa = ri / 2; int left = node[2 * fa].value; int right = node[2 * fa + 1].value; node[fa].value = min(left, right); Update(fa); } int main(){ char ch[5]; int T, n, num; scanf("%d", &T); while (T-- && scanf("%d", &n)){ build(1, 1, Max); while (n--){ scanf("%s", ch); if (ch[0] == 'q'){ if (node[1].value == INF) printf("none\n"); else printf("%d\n", node[1].value); } else{ scanf("%d", &num); if (ch[0] == 'b') node[father[num]].cnt++; else if (ch[0] == 'c') node[father[num]].cnt--; if (node[father[num]].cnt == 1) node[father[num]].value = num; else node[father[num]].value = INF; Update(father[num]); } } } return 0; }
(如有错误,欢迎指出,转载请注明出处)
时间: 2024-10-27 05:20:04