ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HDU 7171 - Range Reachability Query(分块 bitset)

2022-07-27 14:03:59  阅读:177  来源: 互联网

标签:HDU qu int dfrac 复杂度 Reachability Range MAXN omega


题面传送门

一道感觉思路挺自然的题,不知道为什么赛时只有三个队过(?)

首先这题肯定严格强于有向图任意两点连通性对吧,所以此题 std 时间复杂度肯定不低于有向图任意两点连通性的复杂度,即 \(\dfrac{nm}{\omega}\),而此题 \(5\times 10^4\) 的数据范围肯定 \(n^2\) 不可能过,因此 bitset 肯定跑不掉的,关键在于如何 bitset。

一个很自然的想法是将点的可达性看成一个个布尔型变量,从这个角度出发你可以得到 \(114514191981019260817998244353\) 种乱搞,赛时我和 ymx 一直在倒腾这些乱搞,但事实证明没有一个可以过。

正确的压位方式:设 \(f_{i,j}\) 表示从 \(i\) 开始,只经过 \([l_j,r_j]\) 之内的边能否到达 \(v_j\),再设 \(g_{i,j}\) 表示是否有 \(i\in[l_j,r_j]\),注意到 \(f_{i,j},g_{i,j}\) 都只有 \(0/1\) 两种取值,因此可以 01 压位。得到的正确状态设计后,转移就很显然了:\(g_{i,j}\) 可以通过差分得到,求 \(f_{i,j}\) 可以拓扑排序,然后对于每条边 \((u,v,id)\),令 \(f_u\) 为 \(f_u|(f_v\&g_{id})\)。

但是直接这么转移还有一个问题就是空间不太能开得下。\(f_{i,j}\) 空间是 \(\dfrac{nq}{\omega}\) 的,问题不大,但是 \(g_{i,j}\) 空间是 \(\dfrac{mq}{\omega}\) 的,空间常数有亿点点大,这里有一个很套路的方法:把差分的过程看作一个时间轴,然后分块,每 \(B\) 个时刻记录一次每个点的状态,这样如果你需要知道一个 \(g_{i,j}\) 的值,你就从上一次记录的位置开始,每遇到一个修改操作就改下这个位置上的值。这样空间复杂度降到了 \((nq+\dfrac{mq}{B})·\dfrac{1}{\omega}\),时间复杂度 \(\dfrac{nq}{\omega}+qB\),毛估估 \(B=\sqrt{q}\) 最优,但大概 \(B=100\) 就够了。

const int MAXN = 5e4;
const int MAXM = 1e5;
const int BLK = 100;
int n, m, qu, lim, hd[MAXN + 5], to[MAXM + 5], nxt[MAXM + 5], ec = 0;
void adde(int u, int v) {to[++ec] = v; nxt[ec] = hd[u]; hd[u] = ec;}
struct qry {int u, v, l, r;} q[MAXN + 5];
pii eve[MAXN * 2 + 5]; int qn, pos[MAXM + 5];
u64 f[MAXN + 5][MAXN / 64 + 5], cur[MAXN / 64 + 5], mem[MAXN * 2 / BLK + 5][MAXN / 64 + 5];
void clear() {
	for (int i = 1; i <= n; i++) for (int j = 0; j < lim; j++) f[i][j] = 0;
	for (int i = 0; i < lim; i++) cur[i] = 0; ec = 0; qn = 0;
	for (int i = 1; i <= n; i++) hd[i] = 0;
}
void solve() {
	scanf("%d%d%d", &n, &m, &qu); lim = (qu - 1) / 64 + 1; clear();
	for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), adde(u, v);
	for (int i = 0; i < qu; i++) {
		scanf("%d%d%d%d", &q[i].u, &q[i].v, &q[i].l, &q[i].r);
		eve[++qn] = mp(q[i].l, i); eve[++qn] = mp(q[i].r + 1, i);
		f[q[i].v][i >> 6] ^= (1ull << (i & 63));
	}
	sort(eve + 1, eve + qn + 1);
	for (int i = 1; i <= qn; i++) {
		cur[eve[i].se >> 6] ^= (1ull << (eve[i].se & 63));
		if (i % BLK == 0) {
			for (int j = 0; j < lim; j++)
				mem[i / BLK][j] = cur[j];
		}
	}
	for (int i = 1, j = 1; i <= m; i++) {
		while (j <= qn && eve[j].fi <= i) ++j;
		pos[i] = j - 1;
	}
	for (int i = n; i; i--) for (int e = hd[i]; e; e = nxt[e]) {
		int x = pos[e]; static u64 tmp[MAXN / 64 + 5];
		for (int j = 0; j < lim; j++) tmp[j] = mem[x / BLK][j];
		for (int j = x / BLK * BLK + 1; j <= x; j++) tmp[eve[j].se >> 6] ^= (1ull << (eve[j].se & 63));
		for (int j = 0; j < lim; j++) f[i][j] |= (f[to[e]][j] & tmp[j]);
	}
	for (int i = 0; i < qu; i++) printf("%s\n", (f[q[i].u][i >> 6] >> (i & 63) & 1) ? "YES" : "NO");
}
int main() {
	int qu; scanf("%d", &qu);
	while (qu--) solve();
	return 0;
}

标签:HDU,qu,int,dfrac,复杂度,Reachability,Range,MAXN,omega
来源: https://www.cnblogs.com/ET2006/p/HDU-7171.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有