2025.3.27 鲜花

如何优雅的使用 stl

啥背景,杀乌鸡
Viumbe vyote vya mungu wetu na mfalme wetu
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Pazeni sauti
Pazeni sauti
Viumbe vyote vya mungu wetu na mfalme wetu
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Viumbe vyote vya mungu wetu na mfalme wetu
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Pazeni sauti
Pazeni sauti
Pazeni sauti ili nasi mwimbe
Pazeni
Pazeni
Pazeni
PazeniPazeni
Pazeni
Viumbe vyote vya mungu wetu na mfalme wetu
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Pazeni sauti ili nasi mwimbe
Pazeni sauti
Pazeni sauti
Pazeni sauti ili nasi mwimbePazeni sauti
Pazeni sauti
Pazeni sauti
Pazeni sauti

众所周知的,priority_queue 可以通过一下方式传 lambda 比较函数。

auto Cmp = [](int a, int b){return a > b;};
priority_queue<int, vector<int>, decltype(Cmp)> que(Cmp);

有没有不定义 Cmp 的办法呢?

我们用

#include <cxxabi.h>
cout << abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr) << endl;

输出一下 decltype(Cmp) 到底是什么类型,它其实是一个 lambda 的类型,根本没法输出。

我们翻找 priority_queue 的原理,容易发现其调用了一个构造函数

priority_queue(const _Compare& __x, _Sequence&& __s = _Sequence())
    : c(std::move(__s)), comp(__x)
    { std::make_heap(c.begin(), c.end(), comp); }

所以它内置了一个比较对象,而我们传入的第三个参就是其类型,我们可以通过构造函数来初始化这个对象。

于是我们用 function 替换掉 decltype 即可:

priority_queue<int, vector<int>, function<bool(int, int)>> que([](int a, int b){return a > b;});

事实上,我们可以自己写一个类似的东西,形如:

template <class T>
class A{
	T f;
	A() = default;
	A(auto k) : f(k){}
};

注意在 C++20 以前 lambda/function 是不能作为值传入 template 的。

当然你也可以用昨天鲜花的内容转成函数指针来传入。


众所周知,可以用 #define protected public 访问 queuestack 的底层结构,类似:

#define protected public
#include <stack>
#include <queue>
#undef protected
 
queue<int> que;
for(int i = 1; i <= 10; ++i)
	que.emplace(i);
for(int i = 9; ~i; --i)
	cout << que.c[i] << ' ';

这个其实可以扩展。

对于 priority_queue,我们类似做

#define protected public
#include <stack>
#include <queue>
#undef protected
 
priority_queue<int> que;
for(int i = 1; i <= 10; ++i)
	que.emplace(i);
for(int i = 9; ~i; --i)
	cout << que.c[i] << ' ';

发现并不是有序的。

这是因为其内部是通过 make_heap 实现的,详细了解可以直接搜,这里说一下如何让他有序。

sort_heap(que.c.begin(), que.c.end(), less<int>())less<int>()que 的比较函数,注意这里是倒序的。

想还原可以用 make_heap(que.c.begin(), que.c.end(), less<int>())

对于 bitset,我们也可以直接访问,形如:

#define private public
#include <bitset>
#undef private

bitset<10000> s;
s._M_w[i];

默认是用 long 压的,一般是 \(64\),注意就是这个是 private,并且是 ._M_w[]

这样其实就解决了必须手写 bitset 的一个方面。

给出 P11831 [省选联考 2025] 追忆 的代码。甚至比我手写快

Code
/* Local File
in_out/in.in
in_out/out.out
*/
#define private public
#include <bitset>
#undef private
#include <bits/stdc++.h>
using namespace std;
using llt = long long;
using ull = unsigned long long;
using llf = long double;
#define endl '\n'
 
const int N = 1e5 + 3, W = 64, D = N / W + 1, B = 600, S = N / B + 3;
int n, m, q, va[N], vb[N], pa[N], pb[N];

bitset<N> sn[N], ca[S], cb[S];
int bln, id[N], bl[N], br[N];

struct Gph{
	vector<int> to[N];
	void Add(int u, int v){
		to[u].emplace_back(v);
	}
	void ADD(int u, int v){
		Add(u, v), Add(v, u);
	}
	void Clr(){
		for(int i = 1; i <= n; ++i)
			to[i].clear();
	}
#define For_to(u, v, g) for(auto v : g.to[u])
} g, rg;

int rd[N];
void Solve(){
	cin >> n >> m >> q;
	for(int i = 1; i <= m; ++i){
		int u, v; cin >> u >> v;
		g.Add(u, v), ++rd[u], rg.Add(v, u);
	}
	for(int i = 1; i <= n; ++i)
		cin >> va[i], pa[va[i]] = i;
	for(int i = 1; i <= n; ++i)
		cin >> vb[i], pb[vb[i]] = i;
	queue<int> que;
	for(int i = 1; i <= n; ++i) if(!rd[i])
		que.emplace(i);
	while(!que.empty()){
		int u = que.front(); que.pop();
		sn[u][u] = 1;
		For_to(u, v, g) sn[u] |= sn[v];
		For_to(u, v, rg)
			if(!--rd[v]) que.emplace(v);
	}
	bln = 0;
	for(int l = 1; l <= n; l += B){
		++bln;
		for(int j = bl[bln] = l, r = br[bln] = min(l + B - 1, n); j <= r; ++j)
			ca[bln][pa[j]] = 1, cb[bln][pb[j]] = 1, id[j] = bln;
	}
	for(int i = bln - 1; i; --i)
		ca[i] |= ca[i + 1], cb[i] |= cb[i + 1];
	for(int tst = 1; tst <= q; ++tst){
		int op; cin >> op;
		if(op == 1){
			int x, y; cin >> x >> y;
			int ix = id[va[x]], iy = id[va[y]];
			swap(va[x], va[y]), pa[va[x]] = x, pa[va[y]] = y;
			for(int i = 1; i <= ix; ++i) ca[i][x] = 0;
			for(int i = 1; i <= iy; ++i) ca[i][x] = 1;
			for(int i = 1; i <= iy; ++i) ca[i][y] = 0;
			for(int i = 1; i <= ix; ++i) ca[i][y] = 1;
		}else if(op == 2){
			int x, y; cin >> x >> y;
			int ix = id[vb[x]], iy = id[vb[y]];
			swap(vb[x], vb[y]), pb[vb[x]] = x, pb[vb[y]] = y;
			for(int i = 1; i <= ix; ++i) cb[i][x] = 0;
			for(int i = 1; i <= iy; ++i) cb[i][x] = 1;
			for(int i = 1; i <= iy; ++i) cb[i][y] = 0;
			for(int i = 1; i <= ix; ++i) cb[i][y] = 1;
		}else{
			int u, l, r; cin >> u >> l >> r;
			int il = id[l], ir = id[r];
			bitset<N> k(ca[il] ^ ca[ir]);
			for(int i = bl[ir]; i <= r; ++i) k[pa[i]] = 1;
			for(int i = bl[il]; i < l; ++i) k[pa[i]] = 0;
			k &= sn[u];
			int p = 0;
			for(int i = 0; i < D; ++i)
				while(p < bln && (cb[p + 1]._M_w[i] & k._M_w[i])) ++p;
			if(!p) cout << 0 << endl;
			else
				for(int i = br[p]; i >= bl[p]; --i){
					int p = pb[i];
					if(k[p]){
						cout << i << endl;
						break;
					}
				}
		}
	}
}

void Clear(){
	memset(sn, 0, sizeof sn);
	memset(ca, 0, sizeof ca);
	memset(cb, 0, sizeof cb);
	g.Clr(), rg.Clr();
}

int main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int c, t; cin >> c >> t;
	while(t--) Solve(), Clear();
}

众所周知,在 tr2/dynamic_bitset 头文件中有一个 dynamic_bitset,其支持动态 resize

具体可以看 dynamic_bitset

但是众所不周知,其 is_subset_of (话说这个 subset 竟然是后缀)写挂了……

所以你直接用 is_subset_of 会 CE。

5k 曾给出过:

#define is_proper_subset_of is_subset_of(const dynamic_bitset& __b)\
	{ return this->_M_is_subset_of(__b); }\
	bool qwq

我们分析一下原因。

翻找源码:

bool _M_is_subset_of(const __dynamic_bitset_base& __b) noexcept{
	if (__b._M_w.size() == this->_M_w.size()){
	    for (size_t __i = 0; __i < this->_M_w.size(); ++__i)
			if (this->_M_w[__i] != (this->_M_w[__i] | __b._M_w[__i]))
				return false;
	    return true;
	}else return false;
}

bool is_subset_of(const dynamic_bitset& __b) const
	{ return this->_M_is_subset_of(__b); }

容易发现其问题:在 bool _M_is_subset_of(const __dynamic_bitset_base& __b) 后少了一个 const

写源代码不编译的人这辈子有了。

但是我们不太能直接加上一个 const,于是我们曲线救国,把 is_proper_subset_of define 成一个新的 is_subset_of 即可。

这样就不能用 is_proper_subset_of 了(当然也不能用 qwq 做变量名),但事实上是 is_proper_subset_of 的源码更绝望,其有好多错特别不好改,还是用 is_subset_of && != 替代吧。

其实要是只是想用的话有更简单的方式,我们发现 is_subset_of 本质上就是调用了一个 _M_is_subset_of,并且 dynamic_bitset__dynamic_bitset_base 之间可直接转换,所以如下即可:

#define private public
#include <tr2/dynamic_bitset>
#undef private

tr2::dynamic_bitset<> a, b;
a._M_is_subset_of(b);
P




posted @ 2025-03-27 07:49  xrlong  阅读(57)  评论(2)    收藏  举报

Loading