专栏文章
题解:CF1361E James and the Chase
CF1361E题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @min1jmhd
- 此快照首次捕获于
- 2025/12/01 19:03 3 个月前
- 此快照最后确认于
- 2025/12/01 19:03 3 个月前
Sol
不难想到如何判定一个点是不是好点,只要以其为根的 DFS 树上只有树上边和返祖边即可。
但这么判还是太慢了。事实上,当找出一个好点以及相应 DFS 树时,就已经可以找到所有好点了。有结论,除了根节点外,一个点为好点当且仅当其子树中有且仅有一条返祖边指向其祖先,且指向的祖先为好点。这是因为当前已经没有前向边与兄弟边了,故而每个点只需要考虑到其父亲的路径方案数。证明是显然的。树上差分存返祖边数,然后再对每个点记一下可以走到的最浅的祖先即可。
这要求我们找到一个好点,由于题目规定好点数量应超过 ,故而直接随一百个试就行。
Code
CPPconst int N=1e5+5;
int n,m;
vec<int> g[N];
int dfn[N],dcnt,to[N],cf[N],f[N];
bool ins[N];
bool dfs(int x){
dfn[x]=++dcnt;to[dcnt]=x;
ins[x]=1;
for(auto y:g[x]){
if(!dfn[y]){if(!dfs(y))return 0;cf[x]+=cf[y],chmin(f[x],f[y]);}
else if(!ins[y])return 0;
else ++cf[x],--cf[y],chmin(f[x],dfn[y]);
}
ins[x]=0;
return 1;
}
auto rnd=mt19937(10170111);
inline void Main(){
cin>>n>>m;
rep(i,1,n)g[i].clear();
rep(i,1,m){
int a,b;cin>>a>>b;
g[a].pub(b);
}
rep(i,1,100){
int x=rnd()%n+1;
if([&](){
dcnt=0;
rep(i,1,n)dfn[i]=cf[i]=0,f[i]=n+1;
return dfs(x);
}()){
vec<int> ans;
ans.pub(x);ins[1]=1;
rep(i,2,n)if(cf[to[i]]==1&&ins[f[to[i]]])ans.pub(to[i]),ins[i]=1;
if(ans.size()<(n+4)/5)put(-1);
else{
sort(ans.begin(),ans.end());
for(auto i:ans)cout<<i<<" ";
put("");
}
return;
}
}
return put(-1),void();
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...