裸的查分约束,通过它给的条件,可以推出,i比k少,那么建一条i->k的cost=1的边,反之亦然,若i<=k,则建一条i->k,cost=0的边,反之亦然,若相等,则双向建cost=0的边,然后从0号点向每个点点建cost=1的边,然后跑一下最长路,然后累加每一个的dis,因为查分约束问题中存在环无解问题,所以要判断是否存在环
然后就是网上说的从0正逆向向每个点建边防止10W的链的问题,我正向建边,从1->n,没有T ,emmmm
代码
#include<cmath> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int M=400500; int n,m; int dis[M],vis[M],cnt[M]; struct edge { int to,cost; }now; vector<edge>v[M]; bool SPFA() { queue<int>q; q.push(0); while (q.size()) { int u=q.front();q.pop();vis[u]=0; for (int i=0;i<v[u].size();i++) { int go=v[u][i].to; int pay=v[u][i].cost; if (dis[go]<dis[u]+pay) { dis[go]=dis[u]+pay; cnt[go]++; if (cnt[go]>=n) {cout<<"-1";return 0;} if (!vis[go]) { vis[go]=1; q.push(go); } } } } return 1; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int flag,a,b; scanf("%d%d%d",&flag,&a,&b); if (flag==1) now.to=b,now.cost=0,v[a].push_back(now); if (flag==1) now.to=a,now.cost=0,v[b].push_back(now); else if (flag==2) now.to=b,now.cost=1,v[a].push_back(now); else if (flag==3) now.to=a,now.cost=0,v[b].push_back(now); else if (flag==4) now.to=a,now.cost=1,v[b].push_back(now); else if (flag==5) now.to=b,now.cost=0,v[a].push_back(now); if ((flag==2||flag==4)&&(a==b)){cout<<"-1";return 0;} } for (int i=1;i<=n;i++) now.to=i,now.cost=1,v[0].push_back(now); if (SPFA()) { long long int ans=0; for (int i=1;i<=n;i++) ans+=dis[i]; cout<<ans; } return 0; }