题解:CF2008D Sakurako's Hobby

CF2008D 题解

题面

原题传送门

题意

给定一个 01 串,和一个 1n 的排列 pi,称两个数 i,j 是互相到达的,当且仅当 i 可以通过若干次 i=pi 而变成 j,询问对于每个 i,可以到达多少个在字符串中的位置为 0 的点。

思路

看到题目很容易就想到图论,把 ipi 连一条有向边,把题目转换成图上的问题。

首先,因为 pi 是一个 1n 的排列,所以一个数至多指向一个点,一个数也至多被一个点指向。

于是就可以想到,这个图一定是若干个环组成的,而且环与环之间没有边相连。

到了这里,思路就很清晰了,直接跑一遍 tarjan,每个点的答案就是在其所在的强联通分量的点的个数。

代码很板,非常好打。

代码

注:题目要求能到达的 0 的个数,但作者为了方便,所以给取反了,改成求能到达的 1 的个数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define ll long long
using namespace std;
const int MN=2e5+5;
ll n,a[MN],c[MN],head[MN],tot,low[MN],num[MN],dfn,f[MN],sta[MN],top,scc[MN],cnt,val[MN];
char s[MN];
bool vis[MN];
struct edge{
	ll nxt,to;
	void clear(){nxt=to=0;}
}e[MN<<2];
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
void add(ll u, ll v){e[++tot].nxt=head[u];head[u]=tot;e[tot].to=v;}
void init(ll n){
	for(int i=0; i<=tot; i++) e[i].clear();
	for(int i=0; i<=n; i++) head[i]=low[i]=num[i]=sta[i]=scc[i]=val[i]=0;
	top=dfn=cnt=tot=0;
}
void tarjan(ll u){
	low[u]=num[u]=++dfn;sta[++top]=u;
	for(int i=head[u]; i; i=e[i].nxt){
		ll v=e[i].to;
		if(!num[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		} 
		else if(!scc[v]) low[u]=min(low[u],num[v]);
	}
	if(low[u]==num[u]){
		cnt++;
		while(1){
			ll v=sta[top--];
			scc[v]=cnt;val[cnt]+=c[v];
			if(u==v) break;
		}
	}
}
void solve(){
	init(n);
	n=read();
	for(ll i=1; i<=n; i++){
		a[i]=read();
		add(i,a[i]);
	}
	cin>>s;
	for(int i=0; i<n; i++) c[a[i+1]]=s[i]-'0';
	for(int i=1; i<=n; i++) c[i]=c[i]^1;
	for(int i=1; i<=n; i++) if(!num[i]) tarjan(i);
	for(int i=1; i<=n; i++) f[i]=val[scc[i]];
	for(int i=1; i<=n; i++) write(f[i]),putchar(' ');putchar('\n');
}
int main(){
	ll T=read();while(T--) solve();
	return 0;
}
posted @   naroto2022  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
花开如火,也如寂寞。