洛谷P5068[Ynoi2015]我回来了(bfs+bitset)

题目链接

洛谷

题外话

这题的题目背景又让我想起了被致郁一周的恐惧……然后昨晚在床上就脑中重温了一遍……然后就又抑郁了一晚上……

解析

首先边权全为\(1\),那么就可以\(O(n + m)\)\(bfs\)求单源最短路,每个点跑一遍\(bfs\),就可以\(O(n(n + m))\)求出任意两点间距离

直接统计距离小于等于某个值的点不方便,我们考虑先统计恰好等于的点,然后只要前缀和就好了,但是如果只记录点的个数,前缀和就会算重

要想正确求出答案,这个“前缀和”相当于“前缀集合并”,这种集合问题就可以考虑上\(bitset\)试试

\(f[i][j]\)是一个\(bitset\),表示到点\(i\),距离小于等于\(j\)的点的集合,每次\(bfs\)完统计恰好等于的情况,然后从\(0\)开始并上去就行了

我们发现只有最多\(1000\)个点,距离也不会超过点数,那么\(O(\frac{n^3}{8})\)的空间就开得下了

然后大概\(O(\frac{n^3}{32})\)的时间复杂度也是可以过掉这题的

但是此题卡莲式前向星……因为内存不连续导致变慢,不如内存连续的\(vector\)快……

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <bitset>
#include <vector>
#define MAXN 1003
#define MAXM 100003
#define REG register

typedef long long LL;
const int inf = 0x3f3f3f3f;
/*
struct Graph {
	struct Edge {
		int v, next;
		Edge(int _v = 0, int _n = 0):v(_v), next(_n) {}
	} edge[MAXM << 1];
	int head[MAXN], dist[MAXN], cnt;
	void init() { memset(head, -1, sizeof head); cnt = 0; }
	void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; }
	void insert(int u, int v) { add_edge(u, v); add_edge(v, u); }
	void bfs(int);
} G;
*/
std::vector<int> next[MAXN];
int N, M, Q, dist[MAXN];
std::bitset<MAXN> f[MAXN][MAXN], ans;

void bfs(int);
char gc();
int read();
void print(int);
int main() {
	//G.init();
	N = read(), M = read(), Q = read();
	while (M--) {
		int x = read(), y = read();
		//G.insert(x, y);
		next[x].push_back(y);
		next[y].push_back(x);
	}
	for (REG int i = 1; i <= N; ++i) {
		//G.bfs(i);
		bfs(i);
		for (REG int j = 1; j <= N; ++j) if (dist[j] ^ inf) f[i][dist[j]].set(j);
		for (REG int j = 1; j <= N; ++j) f[i][j] |= f[i][j - 1];
	}
	while (Q--) {
		ans.reset();
		int a = read(), x, y;
		while (a--) { x = read(), y = read(); ans |= f[x][std::min(y, N)]; }
		print((int)ans.count()); putchar('\n');
	}

	return 0;
}
//void Graph::bfs(int s) {
void bfs(int s) {
	memset(dist, inf, sizeof dist);
	dist[s] = 0;
	static int que[MAXN];
	REG int hd = 0, tl = 0;
	que[tl++] = s;
	while (hd ^ tl) {
		int p = que[hd++];
		//for (REG int i = head[p]; ~i; i = edge[i].next)
		for (REG int i = 0; i < next[p].size(); ++i)
			if (dist[next[p][i]] == inf) {
				dist[next[p][i]] = dist[p] + 1;
				que[tl++] = next[p][i];
			}
	}
}
inline char gc() {
	static char buf[1000000], *p1, *p2;
	if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
	return p1 == p2 ? EOF : *p2++;
}
inline int read() {
	int res = 0; char ch = gc();
	while (ch < '0' || ch > '9') ch = gc();
	while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
	return res;
}
inline void print(int x) {
	static int buf[20];
	if (!x) putchar('0');
	else {
		while (x) buf[++buf[0]] = x % 10, x /= 10;
		while (buf[0]) putchar('0' + buf[buf[0]--]);
	}
}
//Rhein_E
posted @ 2019-03-11 07:30  Rhein_E  阅读(215)  评论(0编辑  收藏  举报