首页 > 其他分享 >【XSY3325】社保(拓扑序)

【XSY3325】社保(拓扑序)

时间:2022-10-30 11:14:36浏览次数:54  
标签:ch 社保 int 拓扑 ++ low 序比 XSY3325

显然我们先缩点,之后转化为一个 DAG,设为 \(G\),设由其反边构成的图为 \(G'\)。题意就是求所有 “好的” 点,其中一个 “好的” 点需要满足这个点在 \(G\) 上能走到的点和在 \(G'\) 上能走到的点的并集为所有点。

思路 1:显然一个点不可能同时在 \(G\) 和 \(G'\) 上都能被同一个点 \(u\) 走到(除了这个点就是 \(u\)),于是我们可以在 \(G\) 和 \(G'\) 上分别求出 \(u\) 能走到的点的个数,再加起来判断是否等于 \(n+1\)。但你发现这个能走到的点的个数并不好快速求。(如果用 bitset+拓扑 那么与直接暴力无异)

我们可以将限制改的更严一点:我们先对 \(G\) 随便跑一个拓扑序出来,假设点 \(u\) 的拓扑序为 \(a_u\)。那么一个点 \(u\) 如果是 “好的” 点,当且仅当:在 \(G\) 上,拓扑序比 \(u\) 小的点都能走到 \(u\),拓扑序比 \(u\) 大的点 \(u\) 都能走到。

思路 2:注意到这个条件其实告诉了我们一个隐含的信息:某个 “好的” 点 \(u\) 一定满足 \(u\) 在拓扑序的位置唯一。但是在考场上并没有想出来按这个思路做应该怎么做。

我们还是回到原来的要求:一个点 \(u\) 如果是 “好的” 点,当且仅当:在 \(G\) 上,拓扑序比 \(u\) 小的点都能走到 \(u\),拓扑序比 \(u\) 大的点 \(u\) 都能走到。

对于一个点 \(u\),我们可以先考虑哪些点 \(u\) 走不到,那么 \(u\) 走不到的点肯定不是 “好的” 点。我们可以找出 \(u\) 的所有儿子中拓扑序最小的那个点 \(v\),那么拓扑序在 \((a_u,a_v)\) 之间的点 \(u\) 肯定走不到,那么我们对区间 \((a_u,a_v)\) 打上标记。

我们可以同样考虑哪些点走不到 \(u\)。

最后可以证明没有被打上标记的点一定是 ”好的“ 点。

#include<bits/stdc++.h>

#define N 1000010

using namespace std;

inline int read()
{
	int 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^'0');
		ch=getchar();
	}
	return x*f;
}

int n,m;
int cnt=1,head[N],nxt[N<<1],to[N<<1];
int idx,dfn[N],low[N];
int top,sta[N];
int nscc,scc[N];
int num,du[N],a[N];
int c[N];
bool ins[N];
bool cor[N];
bool F;

vector<int>e[N];

void tarjan(int u)
{
	dfn[u]=low[u]=++idx;
	sta[++top]=u,ins[u]=1;
	for(int v:e[u])
	{
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(ins[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		nscc++;
		int v;
		do
		{
			v=sta[top],top--;
			ins[v]=0;
			scc[v]=nscc;
		}while(v!=u);
	}
}

void adde(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}

queue<int>q;

void tuopu()
{
	num=0;
	for(int i=1;i<=nscc;i++)
		if(!du[i]) q.push(i);	
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		a[u]=++num;
		for(int i=head[u];i;i=nxt[i])
		{
			if((i&1)^F) continue;
			int v=to[i];
			du[v]--;
			if(!du[v]) q.push(v);
		}
	}
}

void work()
{
	for(int i=1;i<=nscc;i++) du[i]=0;
	for(int i=2+F;i<=cnt;i+=2) du[to[i]]++;
	tuopu();
	if(num!=nscc)
	{
		puts("0");
		exit(0);
	}
	for(int i=1;i<=nscc;i++) c[i]=0;
	for(int u=1;u<=nscc;u++)
	{
		int minv=0;
		for(int i=head[u];i;i=nxt[i])
		{
			if((i&1)^F) continue;
			if(!minv||a[to[i]]<a[minv]) minv=to[i];
		}
		if(minv) c[a[u]+1]++,c[a[minv]]--;
		else c[a[u]+1]++,c[nscc+1]--;
		int maxv=0;
		for(int i=head[u];i;i=nxt[i])
		{
			if(!((i&1)^F)) continue;
			if(!maxv||a[to[i]]>a[maxv]) maxv=to[i];
		}
		if(maxv) c[a[maxv]+1]++,c[a[u]]--;
		else c[1]++,c[a[u]]--;
	}
	for(int i=1;i<=nscc;i++) c[i]+=c[i-1];
	for(int i=1;i<=nscc;i++) if(c[a[i]]) cor[i]=0;
}

int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		e[u].push_back(v);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) tarjan(i);
	for(int u=1;u<=n;u++)
	{
		for(int v:e[u])
		{
			if(scc[u]!=scc[v])
			{
				adde(scc[u],scc[v]);
				adde(scc[v],scc[u]);
			}
		}
	}
	for(int i=1;i<=nscc;i++) cor[i]=1;
	F=0;work();
	vector<int>ans;
	ans.clear();
	for(int i=1;i<=n;i++)
		if(cor[scc[i]]) ans.push_back(i);
	printf("%d\n",(int)ans.size());
	for(int u:ans) printf("%d ",u);
	return 0;
}
/*
6 7
1 2
1 3
2 4
3 4
4 5
5 6
6 5
*/

标签:ch,社保,int,拓扑,++,low,序比,XSY3325
From: https://www.cnblogs.com/ez-lcw/p/16840748.html

相关文章

  • 实验一:SDN拓扑实践
    一、实验目的1、能够使用源码安装Minet;2、能够使用Mininet的可视化工具生成拓扑3、能够使用Mininet的命令行生成特定拓扑4.能够使用Mininet交互界面管理SDN拓扑;5、能......
  • 实验1:SDN拓扑实践
    实验1:SDN拓扑实践基础要求使用Mininet可视化工具,生成下图所示的拓扑,并保存拓扑文件名为学号.py。使用Mininet的命令行生成如下拓扑:a)3台交换机,每个交换机连接1台......
  • 【ARC083F】Collecting Balls(图论模型,二分图,基环树,拓扑序)
    首先用\(2n\)个点表示每个机器人,原图中的一个球转化为图上的一条边,于是转化为一个二分图模型。我们对这个二分图的每个连通块分开考虑(假设有\(cnt\)个连通块),显然一个......
  • 【AGC010E】Rearranging(博弈,图论,拓扑排序)
    考场上想了很久才想到做法,然后考完后又想了很久,加上看了一下一些大佬的博客和Atcoder的官方题解,才完整地证明了整个做法的正确性。综合了一下,在这里详细阐述:首先发现如......
  • 实验一:SDN拓扑实践
    实验一:SDN拓扑实践一、实验目的1、能够使用源码安装Minet;2、能够使用Mininet的可视化工具生成拓扑3、能够使用Mininet的命令行生成特定拓扑4.能够使用Mininet交互界面......
  • 实验1:SDN拓扑实践
    实验1:SDN拓扑实践一、实验目的能够使用源码安装Mininet;能够使用Mininet的可视化工具生成拓扑;能够使用Mininet的命令行生成特定拓扑;能够使用Mininet交互界面管理SDN拓......
  • 企业社保代缴有什么好处
    社保代缴这个行业逐渐走向成熟,这两年因为疫情又让社保代缴这个行业火了一把!现在不单单只有个人选择社保代缴公司办理业务,有很多个人微小企业也会选择社保代缴公司。个人与企......
  • python | 算法-拓扑排序
    写在前面:我自己用python练习算法与数据结构的典型算法汇总在这里:汇总-算法与数据结构-python版,欢迎翻阅!1️⃣参考链接:https://github.com/algorithmzuo/algorithmbasic......
  • My University Is Better Than Yours (建图 + tj去环缩点 + 拓扑序 )
    题意:给你n所大学,给你m种类型的排名,问你有每一所大学可以比其他多少个大学大,将所有排名都累计上思路:一开始想用bitset做,但是空间爆了根据题意来建图,转化为......
  • 拓扑排序
     拓扑排序是将有向无环图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u、v,如果存在边u->v,那么在序列中u一定在v前面,这个序列又被称为拓扑序列。 注意是将所......