从题面上看,很容易想到是差分约束。
但是发现数据范围比较大,无法判断无解情况(复杂度为O(nm)).
但我们仔细读题,发现:边权只有0/1。
由于是求每个未知量得最小值。
我们建一个超级源点S,d[S]=0,d[x] - d[S] = 1;这样就能保证每颗星星得最小值为1.
然后把条件按最长路建图。(为什么是最长路,可以仔细想一下,我之前差分约束总结里有详细说)
由于是最长路,无解的情况是存在正环,而由于只有0/1,所以某个环上只要有一个1,那么就无解。
也就是说,我们可以在建图时先判断是否有解,再用spfa跑最长路即可。
判环上是否有边权为1,可以先求出图的SCC,在每个SCC上遍历所有边,只要存在边权为1,则无解。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
int head[M],cnt=1,hc[M],tc=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2],ec[M];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
void add_c(int x,int y,int w)
{
ec[++tc].nxt=hc[x];
ec[tc].to=y;
ec[tc].w=w;
hc[x]=tc;
}
int dfn[M],low[M];
int sk[M],top,ct,sz,in[M],c[M];
vector<int>scc[M];
int vs[M],d[M];
void tarjan(int x)
{
low[x]=dfn[x]=++sz;
sk[++top]=x,in[x]=1;
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(in[y])low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
ct++;int y;
do{
y=sk[top--],in[y]=0;
c[y]=ct,scc[ct].pb(y);
}while(x!=y);
}
}
void spfa()
{
queue<int>q;q.push(0);vs[0]=1;
while(q.size())
{
int x=q.front();q.pop();
vs[x]=0;
// cout<<x<<" - "<<endl;
for(int i=hc[x];i;i=ec[i].nxt)
{
int y=ec[i].to,w=ec[i].w;
// cout<<x<<" "<<y<<" "<<w<<" "<<d[y]<<" "<<d[x]<<endl;
if(d[y]<d[x]+w)
{
d[y]=d[x]+w;
if(!vs[y])q.push(y),vs[y]=1;
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y,t;
cin>>t>>x>>y;
//d[v]-d[u]>=w / u -> v : w
if(t==1)add(x,y,0),add(y,x,0);
if(t==2)add(x,y,1);//d[x]<d[y] / d[y]-d[x]>=1
if(t==3)add(y,x,0);//d[x]>=d[y] / d[x]-d[y]>=0
if(t==4)add(y,x,1);//d[x]>dy] / d[x]-d[y]>=1
if(t==5)add(x,y,0);//d[x]<=d[y]
}
//不能存在 环上边权为1的情况。
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
bool f=true;
for(int i=1;i<=ct;i++)
for(auto x:scc[i])
for(int j=head[x];j;j=ee[j].nxt)
{
if(c[ee[j].to]!=i)continue;
// cout<<x<<" "<<ee[j].to<<" "<<c[x]<<" "<<c[ee[j].to]<<" "<<ee[j].w<<endl;
if(ee[j].w==1)f=false;
}
if(!f){
cout<<-1<<endl;
return 0;
}
for(int x=1;x<=n;x++)
{
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to,w=ee[i].w;
if(c[x]==c[y])continue;
add_c(c[x],c[y],w);
}
}
for(int i=1;i<=ct;i++)add_c(0,i,1);//超级源点,保证了每颗星星的亮度大于等于1
spfa();
ll ans=0;
for(int i=1;i<=n;i++)ans+=d[i]*scc[i].size();
cout<<ans<<endl;
return 0;
}