CF1142E Pink Floyd强连通分量,构造
Posted athousandmoons
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1142E Pink Floyd强连通分量,构造相关的知识,希望对你有一定的参考价值。
又是一道交互题
题目描述:你有一个 (n) 个点的竞赛图,有 (m) 条边为粉红色,其余为绿色。粉红色边的方向已知,绿色边方向未知,但你可以询问不超过 (2n) 次一条边 ({u,v}),交互器会告诉你这条边的方向。求一个点 (u),使得对于任意 (v eq u),(u) 可以只经过一种颜色的边到达 (v)。
数据范围:(n,mle 10^5)。
解法实在有点绕...
首先如果 (m=0),我们维护一个答案集合 (S) 表示目前可能的答案。一开始 (S=V),之后要一步步排除。若 ((u,v)in E),则 (v) 是答案 (Rightarrow u) 是答案。所以可以不考虑 (v),把 (v) 从 (S) 中删掉。最后只剩下一个点就是答案。
但是如果有粉红色边的话,有一些边就不能用了,但是答案点可以通过粉红色边与其他点联通。所以先把粉红色边缩点,每个强连通分量中只取出一个点加入初始的 (S),然后按照上面的方法做。
但是如果 ((u,v)in E) 则不能直接将 (v) 删掉,因为 (v) 所在的强连通分量由粉红色边组成,不能和绿色边在一条路径中。
于是你可以把每个强连通分量中的一些边删掉使得它成为一个 DAG,每次把入度为 (0) 的点加入,询问得到 ((u,v)in E) 时把 (v) 删掉,再看剩下的点中有没有入度为 (0) 的点加入。剩下的最后一个点就是答案。
正确性证明:被删过的点可以通过绿边到达,没有被删过的点可以通过粉红色边到达。于是 (n-1) 次询问就可以直接搞定?
#include<bits/stdc++.h>
#define Rint register int
#define MP make_pair
#define PB push_back
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 100003, mod = 998244353;
inline int ksm(int a, int b){
int res = 1;
for(;b;b >>= 1, a = (LL) a * a % mod) if(b & 1) res = (LL) res * a % mod;
return res;
}
template<typename T>
inline void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < ‘0‘ || ch > ‘9‘;ch = getchar()) f |= ch == ‘-‘;
for(;ch >= ‘0‘ && ch <= ‘9‘;ch = getchar()) x = x * 10 + ch - ‘0‘;
if(f) x = -x;
}
template<typename T>
inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
inline bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int n, m, cnt, head[N], to[N], nxt[N], deg[N];
bool ins[N], vis[N];
vector<int> E[N], now;
inline void add(int a, int b){to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;}
void dfs(int x){
ins[x] = vis[x] = true;
for(Rint i = head[x];i;i = nxt[i]){
if(!ins[to[i]]){E[x].PB(to[i]); ++ deg[to[i]];}
if(!vis[to[i]]) dfs(to[i]);
}
ins[x] = false;
}
int main(){
read(n); read(m);
for(Rint i = 1, a, b;i <= m;++ i){
read(a); read(b); add(a, b);
}
for(Rint i = 1;i <= n;++ i) if(!vis[i]) dfs(i);
for(Rint i = 1;i <= n;++ i) if(!deg[i]) now.PB(i);
while(now.size() > 1){
int u = now.back(); now.pop_back();
int v = now.back(), f; now.pop_back();
printf("? %d %d
", u, v); fflush(stdout);
scanf("%d", &f); if(f) swap(u, v); now.push_back(v);
for(Rint w : E[u]) if(!-- deg[w]) now.PB(w); E[u].clear();
}
printf("! %d
", now.front()); fflush(stdout);
}
以上是关于CF1142E Pink Floyd强连通分量,构造的主要内容,如果未能解决你的问题,请参考以下文章
CF949C Data Center Maintenance Tarjan找强连通分量
CF711DDirected Roads(想法题,环,强连通分量)