最终得对抗自己

[杂项] 一个难以察觉的错误

前言

能在考试时鼓捣出这种批事, 我真是太佩服自己啦!

正文

考BJOI2018 Day1的题目, 用鬼畜的11标记线段树+set+树状数组写第一题正解, 写完250行, 过样例, 肉眼检查出一个错误, 交, 爆零。

之后百思不得其解, 发现我的程序就算只回答询问, 交换不同query的顺序也会输出不同结果???

query里面应该完全不带修改的啊! 我™一个赋值语句都看不到啊!

调试, 发现执行流程没有问题, 内存不可能溢出导致写爆全局变量, excuse me?

然后…我看到了这玩意…

set st;
...
int ql = (IBT::ql = getInt());
int qr = (IBT::qr = getInt());
int len = qr-ql+1;
LL ans = (LL)len*(len+1)/2;
set<Unit>::iterator lb, rb;
lb = st.lower_bound(ql); // ???
rb = st.lower_bound(qr+1);
...

我的 set<Unit> 的 lower_bound() 参数竟然可以接受 int ? smg? 为什么不报编译错误?为什么我会这样写?

Unit 实际上是一个封装了单个 int 变量的结构体, 比较规则和 int 比较规则完全一样(那你问我为什么要写这个结构体?因为一开始准备封装三个int但是考虑到set的iterator是const类型不能做出修改于是删了两个, 然后就没改回去…), 仔细想了一下如果用 ql, qr 构造 Unit 来作为参数也恰好没有问题。打代码时应该是手残了。

问题来了, 如此手残是怎么通过编译的…

看到 Unit 结构体声明:

...
int ulv[MAXN], urv[MAXN];
struct Unit {
	int p;
	Unit (int a = 0, int b = 0, int c = 0):
	p(a) {ulv[p] = b, urv[p] = c;}
} ;
inline bool operator < (const Unit & a, const Unit & b) {
	return a.p < b.p;
}
...

淦, 图方便写的三参数构造函数+初值被识别为强制类型转换了!

ulv 和 urv 两个数组本来是准备放在 Unit 内部绑定的, 但是为了能够通过 set 的 const iterator 修改 ulv 和 urv 就吧这两货开在全局变量里, 为了体现绑定性在构造函数里面和 Unit 一起进行赋值。

后来又为了图方便能够不赋值构造 Unit 于是把构造函数参数加入了默认值, 但是万万没想到强制类型转换也会调用这个带初值的三参数构造函数!

从而一个不经意的手残就这么通过编译, 调用了强制类型转换, 从而调用了构造函数, 从而修改全局变量。

然后恰好这个错误不太严重, 规模小的数据程序不会出问题, 肉眼检查不出, 数据稍微大一点就爆炸!

冒汗, 当我悲桑地把这个错误修正之后…评测…

0分→100分

/吐血

Join the discussion

Your email address will not be published. Required fields are marked *