思路
这道题比第三题稍微简单一点。
首先我们要把所有的"大于"“大于等于”“不大于”“不小于”转换成“小于”和“小于等于”。
然后就把小的向大的连一条边,如果相等就连双向边。
然后就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;
}