luogu P5676 [GZOI2017]小z玩游戏 |Tarjan+技巧优化建图

题目描述

小 z 很无聊。

小 z 要玩游戏。

小 z 有NNN个新游戏,第iii个游戏看上去的有趣程度为wiw_iwi​。

小 z 很挑,他只会玩看上去的有趣程度是自己兴奋程度整数倍的游戏。

由于游戏实际上有好玩的也有不好玩的,玩完第iii个游戏后,小 z 的兴奋程度会变为eie_iei​。

已知小 z 初始兴奋程度为111,请问小 z 有多少个游戏可能会玩两次?
输入格式

第一行一个正整数TTT,表示测试数据组数,最多101010组。

对于每组测试数据:

第一行一个正整数NNN,表示游戏的个数。
第二行NNN个正整数,第iii个数wiw_iwi​,表示第iii个游戏看上去的有趣程度为wiw_iwi​。
第三行NNN个正整数,第iii个数eie_iei​,表示小 z 玩完第iii个游戏后,小 z 的兴奋程度会变为eie_iei​。

输出格式

共TTT行。

每行一个正整数,表示对应测试数据,小 z 可能会玩两次的游戏数量。


一个数组初始化问题,改了我一天..

建虚点,模拟找倍数过程

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+1,M=80*N;
int nxt[M],head[N],go[M],tot;
inline void add(int u,int v){
	nxt[++tot]=head[u];head[u]=tot;go[tot]=v;
}
int n;
bool vis[N];
int dfn[N],low[N],co[N],st[N],top,col,num;
inline void clear(){
	memset(head,0,sizeof(head));
	memset(vis,0,sizeof(vis));
	memset(nxt,0,sizeof(nxt));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(co,0,sizeof(co));
	col=0; num=0; tot=0;
}
void Tarjan(int u){
	st[++top]=u;
	dfn[u]=low[u]=++num;
	for(int i=head[u];i;i=nxt[i]){
		int v=go[i];
		if(!dfn[v]){
			Tarjan(v); 
			low[u]=min(low[u],low[v]);
		}else if(!co[v]) 
		low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		co[u]=++col;
		int siz=1;
		while(st[top]!=u){
			co[st[top]]=col;
			vis[st[top]]=1;
			siz++;
			top--;
		}
		if(siz>1)vis[u]=1;
		--top;
	}
}
signed main(){
	int T; cin>>T;
	while(T--){
		scanf("%d",&n);  
		int Max=0;
		for(int i=1,x;i<=n;i++)scanf("%d",&x),add(n+x,i),Max=max(Max,x);
		for(int i=1,x;i<=n;i++)scanf("%d",&x),add(i,n+x);
		for(int i=1;i<=Max;i++)for(int j=2;j*i<=Max;j++)
			add(n+i,n+i*j);
		
		for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
		
		int ans=0;
		for(int i=1;i<=n;i++)if(vis[i])ans++;

		printf("%d\n",ans);
		clear();
	}
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/12669604.html