YbtOJ 强连通分量课堂过关 例4 恒星的亮度【Tarjan】

在这里插入图片描述


思路

这道题比第三题稍微简单一点。
首先我们要把所有的"大于"“大于等于”“不大于”“不小于”转换成“小于”和“小于等于”
然后就把小的向大的连一条边,如果相等就连双向边。
然后就Tarjan缩点,发现相等的数会在同一个强连通分量里,所以就可以判断当一个强连通分量里出现“小于”那么就矛盾,输出-1。
这样做完之后入度为0的点(因为是一个DAG所以一定会有入读为0的点)一定是最小的点。
然后就从入度为0的点开始拓扑,在拓扑的时候不断更新点的值就好了。(为了满足所有边的情况,当前点要取 max ⁡ \max max

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
long long dfn[100010],low[100010],v[100010],vq[100010],cnt[100010],r[100010],timen,sc;
long long hd[100010],tot,hd1[100010],tot1,ans[100010],maxn;
long long stack[100010],tail;
long long n,m,cx,cy,t;
queue<long long> q;
struct node
{
	long long x,to,next,pd;
}a[1000010];
struct node1
{
	long long x,to,next,pd;
}a1[1000010];
void add(long long x,long long y,long long pd)
{
	a[++tot]=(node){x,y,hd[x],pd};
	hd[x]=tot;
}
void add1(long long x,long long y,long long pd)
{
	a1[++tot1]=(node1){x,y,hd1[x],pd};
	hd1[x]=tot1;
}
void tarjan(long long x)
{
	low[x]=dfn[x]=++timen;
	stack[++tail]=x;
	v[x]=1;
	for(long long i=hd[x]; i; i=a[i].next)
	 {
	 	long long yy=a[i].to;
	 	if(!dfn[yy])
	 	 {
	 	 	tarjan(yy);
	 	 	low[x]=min(low[x],low[yy]);
		 }
		else if(v[yy])
		  low[x]=min(low[x],dfn[yy]);
	 }
	if(low[x]==dfn[x])
	 {
	 	sc++;
	 	while(x!=stack[tail+1])
	 	 {
	 	 	vq[stack[tail]]=sc;
	 	 	v[stack[tail]]=0;
	 	 	cnt[sc]++;
	 	 	tail--;
		 }
	 }
}
void tp()
{
	for(long long i=1; i<=sc; i++)
	  {
	    if(!r[i])
	      q.push(i);
	  	ans[i]=1;
	  }
	while(!q.empty())
	 {
	 	long long dx=q.front();
	 	q.pop();
	 	maxn=maxn+ans[dx]*cnt[dx];
	 	//cout<<ans[dx]<<" ";
	 	for(long long i=hd1[dx]; i; i=a1[i].next)
	     {
	     	long long yy=a1[i].to;
	     	ans[yy]=max(ans[yy],ans[dx]+a1[i].pd);
	     	r[yy]--;
	     	if(!r[yy])
	     	  q.push(yy);
		 }
	 }
}
int main()
{
	cin>>n>>m;
	for(long long i=1; i<=m; i++)
	 {
	 	scanf("%lld%lld%lld",&t,&cx,&cy);
	 	if(t==1)
	 	  add(cx,cy,0),add(cy,cx,0); 
	 	else if(t==2)
	 	  add(cx,cy,1);
	 	else if(t==3)
	 	  add(cy,cx,0);
	 	else if(t==4)
	 	  add(cy,cx,1);
	 	else if(t==5)
	 	  add(cx,cy,0);
	 }
	for(long long i=1; i<=n; i++)
	 if(!dfn[i])
	   tarjan(i);
	for(long long i=1; i<=tot; i++)
	 if(vq[a[i].x]!=vq[a[i].to])
	  {
	  	 add1(vq[a[i].x],vq[a[i].to],a[i].pd);
	  	 r[vq[a[i].to]]++;
	  }
	 else if(a[i].pd)
	  {
	  	 printf("-1");
	  	 return 0;
	  }
	tp();
	cout<<maxn;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值