题解 [CF1142E] Pink Floyd

传送门

题又读错了,两种题意都不会做 /kk

我读成啥了?

题目描述

给定一张 n 个点的竞赛图。边是有向边,但你不知道方向。

每次询问,你可以获得一条边的方向。

要求出可以到达其余所有点的点的个数。

保证边的方向均匀随机且不随你的询问而改变。

n105

求一个期望复杂度较小的做法



然后回到原题:
m=0 怎么做呢?
题解建了叶向树形图,于是引出了正解
我胡了个贪心,所以后面死活不会(捂脸
任选一个点为 now,重复一下过程 n1 次:
任选一个未选过的点,询问与 now 之间边的方向
然后令 now 为这条边的起点
想想就知道为啥了

题解维护了所有可能成为答案的叶向树形图的根节点集合
每次任选两个根节点合并
然后考虑这个东西怎么处理有粉色边的情况
那么所有的点可以按照一个关于粉色边的类似拓扑序的顺序加入集合(因为可能有环所以是类似
有环怎么办呢?tarjan 缩点,每个 scc 同时只能有一个点在集合中
于是可以 O(n+m)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define pb push_back
#define ll long long
//#define int long long

int n, m;
queue<int> q;
bool ins[N], vis[N];
vector<int> lst[N];
priority_queue<int> s;
int head[N], dfn[N], low[N], bel[N], sta[N], cnt[N], top, tot, ecnt, now;
struct edge{int from, to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={s, t, head[s]}; head[s]=ecnt;}
inline int query(int u, int v) {int ans; cout<<"? "<<u<<' '<<v<<endl; fflush(stdout); cin>>ans; return ans;}

void tarjan(int u) {
	dfn[u]=low[u]=++tot;
	ins[sta[++top]=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]) {
		++now;
		do {
			ins[sta[top]]=0;
			bel[sta[top--]]=now;
		} while (sta[top+1]!=u);
	}
}

void del(int u) {
	// cout<<"del: "<<u<<endl;
	if (lst[bel[u]].size()) s.push(lst[bel[u]].back()), lst[bel[u]].pop_back();
	else vis[bel[u]]=0;
	for (int i=head[u],v; ~i; i=e[i].next) if (v=e[i].to, bel[v]!=bel[u]&&--cnt[v]==0) {
		if (vis[bel[v]]) lst[bel[v]].pb(v);
		else s.push(v), vis[bel[v]]=1;
	}
}

signed main()
{
	cin>>n>>m;
	memset(head, -1, sizeof(head));
	for (int i=1,u,v; i<=m; ++i) cin>>u>>v, add(u, v);
	for (int i=1; i<=n; ++i) if (!dfn[i]) tarjan(i);
	for (int i=1; i<=m; ++i) if (bel[e[i].from]!=bel[e[i].to]) ++cnt[e[i].to];
	for (int i=1; i<=n; ++i) if (!cnt[i]) {
		if (vis[bel[i]]) lst[bel[i]].pb(i);
		else s.push(i), vis[bel[i]]=1;
	}
	// cout<<"siz: "<<s.size()<<endl;
	while (s.size()>1) {
		int u=s.top(); s.pop();
		int v=s.top(); s.pop();
		if (!query(u, v)) swap(u, v);
		del(v); s.push(u);
	}
	cout<<"! "<<s.top()<<endl;
	fflush(stdout);

	return 0;
}
posted @   Administrator-09  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示