题解 寻宝

传送门

发现这个传送门是单向的就很烦
于是并查集缩点+有向图tarjan缩点+bitset可达性统计即可

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#define int long long

int n, m, k, q;
int dsu[N];
char s[N];
bool **mp;
pair<int, int> door[N];
vector<pair<int, int>> to[N];
const int dlt[][2]={{-1,0},{1,0},{0,1},{0,-1}};
inline int num(int x, int y) {return (x-1)*m+y;}
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}

namespace force{
	bool vis[1010][1010];
	queue<pair<int, int>> q2;
	void bfs(int s, int t) {
		vis[s][t]=1;
		q2.push(make(s, t));
		while (q2.size()) {
			pair<int, int> u=q2.front(); q2.pop();
			// cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
			for (int i=0; i<4; ++i) {
				int x=u.fir+dlt[i][0], y=u.sec+dlt[i][1];
				// cout<<"xy: "<<x<<' '<<y<<' '<<n<<' '<<m<<' '<<mp[x][y]<<endl;
				if (x>=1&&x<=n&&y>=1&&y<=m&&!mp[x][y]&&!vis[x][y]) {
					// cout<<"live: "<<x<<' '<<y<<endl;
					vis[x][y]=1;
					q2.push(make(x, y));
					for (auto it:to[num(x, y)]) if (!vis[it.fir][it.sec]) {
						vis[it.fir][it.sec]=1; q2.push(make(it.fir, it.sec));
					}
				}
			}
		}
	}
	void solve() {
		for (int i=1,x1,y1,x2,y2; i<=q; ++i) {
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			memset(vis, 0, sizeof(vis));
			bfs(x1, y1);
			printf("%d\n", vis[x2][y2]);
		}
		exit(0);
	}
}

namespace task1{
	int head[N], size;
	int dfn[N], low[N], sta[N], top, tot;
	int left[N], id[N], deg[N], ltop;
	bitset<25100> s[25100];
	bool ins[N], vis[N];
	map<pair<int, int>, bool> mp2;
	queue<int> q2;
	struct edge{int to, next;}e[N<<1];
	inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
	inline void uni(int s, int t) {if (find(s)!=find(t)) dsu[find(s)]=find(t);}
	void tarjan(int u) {
		dfn[u]=low[u]=++tot;
		sta[++top]=u;
		ins[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!dfn[v]) {
				tarjan(v);
				low[u]=min(low[u], low[v]);
			}
			else if (ins[v]) low[u]=min(low[u], dfn[v]);
		}
		if (low[u]==dfn[u]) {
			do {
				uni(sta[top], u);
				ins[sta[top--]]=0;
			} while (sta[top+1]!=u);
		}
	}
	void solve() {
		// cout<<double(sizeof(s)+sizeof(head)*7+sizeof(ins)*2+sizeof(e)+sizeof(dsu)+sizeof(door)+sizeof(to))/1000/1000<<endl; return ;
		for (int i=1; i<N; ++i) dsu[i]=i;
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=m; ++j) if (!mp[i][j]) {
				for (int k=0; k<4; ++k) {
					int x=i+dlt[k][0], y=j+dlt[k][1];
					if (x>=1&&x<=n&&y>=1&&y<=m&&!mp[x][y]) {
						int f1=find(num(i, j)), f2=find(num(x, y));
						dsu[f1]=dsu[f2];
					}
				}
			}
		}
		memset(head, -1, sizeof(head));
		for (int i=1; i<=k; ++i) {
			int f1=find(door[i].fir), f2=find(door[i].sec);
			if (f1==f2) continue;
			add(f1, f2);
		}
		for (int i=1; i<=n*m; ++i) if (!vis[find(i)]) left[++ltop]=find(i), vis[find(i)]=1;
		for (int i=1; i<=ltop; ++i) if (!dfn[left[i]]) tarjan(left[i]);
		memset(vis, 0, sizeof(vis)); tot=ltop=0;
		for (int i=1; i<=n*m; ++i) if (!vis[find(i)]) left[++ltop]=find(i), vis[find(i)]=1, id[left[ltop]]=++tot;
		memset(head, -1, sizeof(head)); size=0;
		for (int i=1; i<=k; ++i) {
			// cout<<"dor: "<<door[i].fir<<' '<<door[i].sec<<endl;
			int s=id[find(door[i].fir)], t=id[find(door[i].sec)];
			// cout<<"st: "<<s<<' '<<t<<endl;
			if (s==t || mp2.find(make(s, t))!=mp2.end()) continue;
			add(s, t); mp2[make(s, t)]=1; ++deg[t];
		}
		for (int i=1; i<=ltop; ++i) if (!deg[i]) q2.push(i);
		while (q2.size()) {
			int u=q2.front(); q2.pop();
			s[u][u]=1;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				s[v]|=s[u];
				if (--deg[v]==0) q2.push(v);
			}
		}
		for (int i=1,x1,y1,x2,y2; i<=q; ++i) {
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			int f1=id[find(num(x1, y1))], f2=id[find(num(x2, y2))];
			// cout<<"f: "<<f1<<' '<<f2<<endl;
			if (f1==f2 || s[f2][f1]) puts("1");
			else puts("0");
		}
		exit(0);
	}
}

signed main()
{
	freopen("treasure.in", "r", stdin);
	freopen("treasure.out", "w", stdout);

	scanf("%d%d%d%d", &n, &m, &k, &q);
	mp = new bool*[n+2];
	for (int i=0; i<=n+1; ++i) {
		mp[i]=new bool[m+2];
		for (int j=0; j<=m+1; ++j) mp[i][j]=0;
	}
	for (int i=1; i<=n; ++i) {
		scanf("%s", s+1);
		for (int j=1; j<=m; ++j) mp[i][j]=s[j]=='#'?1:0;
	}
	for (int i=1,x1,y1,x2,y2; i<=k; ++i) {
		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
		door[i]=make(num(x1, y1), num(x2, y2));
		to[num(x1, y1)].pb(make(x2, y2));
	}
	task1::solve();
	// force::solve();

	return 0;
}
posted @ 2021-11-14 19:41  Administrator-09  阅读(1)  评论(0编辑  收藏  举报