一些卡常的方法
查看原帖
一些卡常的方法
678877
Pengzt楼主2023/11/22 15:33
  1. 缩减二分值域,把 O(nlog⁡2log⁡v)\mathcal{O}(n\log^2\log v) 变成 O(nlog⁡3n)\mathcal{O}(n\log^3n)。

  2. 用 zkw 线段树替换常规线段树。

  3. 可以记录下整个点分树的形态,这样就不用每次找根节点了。

  4. 在对单棵分治树进行 getdep 时,可以在 dep>Rdep > R 后直接返回。

  5. 可以记录下每个分治树内部遍历的顺序,用栈记录,这样就递归次数的常数可以减少一半。

  6. 线段树只需记录 max⁡val\max val,在查询时记录下其中一个端点,另一个端点可以最后再 DFS 一遍求得。

  7. 火车头可能有用。

  8. 快读快写可能有用。

具体卡常的细节可以看代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define vi vector<int>
#define eb emplace_back
#define pii pair<int, ll>
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
bool Mbe;
mt19937_64 rng(35);
constexpr int N = 1e5 + 10, inf = 1e9;
int n, m, L, R, res, rt, la, ra, RT;
int b[N], mx[N], sz[N], vis[N], rr[N << 1];
int head[N], cnt_e = 1;
struct edge {
	int to, w, nxt;
} e[N << 1];
void adde(int u, int v, int w) {
	++cnt_e, e[cnt_e].to = v, e[cnt_e].w = w, e[cnt_e].nxt = head[u], head[u] = cnt_e;
}
int val[(1 << 18) + 10], D;
void modify(int x, int v, int type) {
	x += D;
	if(type == 0) val[x] = v;
	else val[x] = max(val[x], v);
	for(int i = x >> 1; i; i >>= 1)
		val[i] = max(val[i << 1], val[i << 1 | 1]);
}
int query(int l, int r) {
	int res = -inf;
	for(l += D - 1, r += D + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if(~l & 1) res = max(res, val[l ^ 1]);
		if(r & 1) res = max(res, val[r ^ 1]);
	}
	return res;
}
int mm;
int gv(int x) {
	return (x >= mm) ? 1 : -1;
}
void findroot(int u, int ff, int num) {
	sz[u] = 1, mx[u] = 0;
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == ff || vis[v]) continue;
		findroot(v, u, num);
		sz[u] += sz[v];
		mx[u] = max(mx[u], sz[v]);
	}
	mx[u] = max(mx[u], num - sz[u]);
	if(mx[u] < mx[rt]) rt = u;
}
int tp;
pii stk[N];
void calc(int u, int ff, int w, int dep) {
	if(dep > R) return;
	stk[++tp] = pii(dep, w);
	if(dep < R && query(max(L - dep, 1), R - dep) + w >= 0) {
		res = 1;
		la = u;
		return;
	}
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == ff || vis[v]) continue;
		calc(v, u, w + gv(e[i].w), dep + 1);
		if(res) return;
	}
}
void divide(int u) {
	vis[u] = 1;
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(vis[v]) continue;
		int tmp = tp;
		calc(v, u, gv(e[i].w), 1);
		if(res) {
			while(tmp) modify(stk[tmp--].fi, -inf, 0);
			tp = 0;
			return;
		}
		for(int j = tmp + 1; j <= tp; ++j)
			modify(stk[j].fi, stk[j].se, 1);
	}
	if(query(L, R) >= 0) {
		res = 1;
		la = u;
	}
	while(tp) modify(stk[tp--].fi, -inf, 0);
	if(res) return;
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(vis[v]) continue;
		divide(rr[i]);
	}
}
bool check(int mid) {
	mm = mid;
	for(int i = 1; i <= n; ++i) vis[i] = 0;
	res = 0;
	divide(RT);
	return res;
}
void getra(int u, int ff, int w, int dep) {
	if(w >= 0 && ff && L <= dep && dep <= R) {
		ra = u;
		return;
	}
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == ff) continue;
		getra(v, u, w + gv(e[i].w), dep + 1);
		if(ra > 0) return;
	}
}
void init(int u) {
	vis[u] = 1;
	for(int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(vis[v]) continue;
		rt = 0;
		findroot(v, u, sz[v]);
		rr[i] = rt;
		init(rr[i]);
	}
}
bool Med;
int main() {
	fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
	ios :: sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> L >> R;
	D = 1 << (__lg(n + 1) + 1);
	for(int i = 0; i < (1 << 18) + 10; ++i) val[i] = -inf;
	int mxw = 0;
	for(int i = 1; i < n; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		b[i] = w;
		mxw = max(mxw, w);
		adde(u, v, w);
		adde(v, u, w);
	}
	rt = 0;
	mx[0] = N;
	findroot(1, 0, n);
	RT = rt;
	init(RT);
	sort(b + 1, b + n);
	m = unique(b + 1, b + n) - b - 1;
	for(int i = 1; i <= cnt_e; ++i) e[i].w = lower_bound(b + 1, b + m, e[i].w) - b;
	int L = 1, R = m;
	while(L <= R) {
		int mid = (L + R) >> 1;
		if(check(mid)) L = mid + 1;
		else R = mid - 1;
	}
	check(R);
	getra(la, 0, 0, 0);
	cout << la << " " << ra << "\n";
	cerr << TIME << "ms\n";
	return 0;
}
2023/11/22 15:33
加载中...