思路
按照题意建边,若亮度大于等于
的,连有向边
,大于则为
,相等则为
.
然后缩点,如果出现一个强连通子图内有大于0的边,说明存在正环,无解.
然后拓扑排序,若有边,
,直接DAG上DP即可.
当然你想跑差分约束我也没办法qwq.
代码
话说那时候脑子抽了还是怎么样,本地运行爆栈了,我还以为一定要手工栈什么的qwq.... 没救了没救了
#include<bits/stdc++.h> using namespace std; #define MAXN 200005 #define MAXM 300005 #define LL long long int N, K; int hd[MAXN], nxt[MAXM], to[MAXM], val[MAXM], tot(1); int dfn[MAXN], low[MAXN], num, c[MAXN], cnt, stk[MAXN], tp, s[MAXN], f[MAXN]; int X, A, B; int o[MAXN], sm, in[MAXN]; void Add( int x, int y, int z ){ nxt[++tot] = hd[x]; hd[x] = tot; to[tot] = y; val[tot] = z; } struct sta{ int x, stp; }; sta make( int xx, int yy ){ sta t; t.x = xx; t.stp = yy; return t; } stack<sta> S; void Tarjan( int xx ){ S.push(make( xx, -1 )); while( !S.empty() ){ sta cur(S.top()); S.pop(); int x(cur.x); if ( cur.stp == -1 ){ dfn[x] = low[x] = ++num; stk[++tp] = x; bool fg(1); for ( int i = hd[x]; i; i = nxt[i] ) if ( !dfn[to[i]] ){ cur.stp = i, S.push( cur ); S.push( make( to[i], -1 ) ); fg = 0; break; } else if ( !c[to[i]] ) low[x] = min( low[x], dfn[to[i]] ); if ( fg && low[x] == dfn[x] ){ c[x] = ++cnt, s[cnt]++; while( stk[tp] != x ) c[stk[tp--]] = cnt, s[cnt]++; tp--; } } else{ low[x] = min( low[x], low[to[cur.stp]] ); bool fg(1); for ( int i = nxt[cur.stp]; i; i = nxt[i] ) if ( !dfn[to[i]] ){ cur.stp = i, S.push( cur ); S.push( make( to[i], -1 ) ); fg = 0; break; } else if ( !c[to[i]] ) low[x] = min( low[x], dfn[to[i]] ); if ( fg && low[x] == dfn[x] ){ c[x] = ++cnt, s[cnt]++; while( stk[tp] != x ) c[stk[tp--]] = cnt, s[cnt]++; tp--; } } } } queue<int> Q; void topo(){ for ( int i = N + 1; i <= cnt; ++i ) if ( in[i] == 0 ) Q.push(i); while( !Q.empty() ){ int t(Q.front()); Q.pop(); for ( int i = hd[t]; i; i = nxt[i] ){ in[to[i]]--; if ( in[to[i]] == 0 ) Q.push( to[i] ); } o[++sm] = t; } } int main(){ scanf( "%d%d", &N, &K ); cnt = N; for ( int i = 1; i <= K; ++i ){ scanf( "%d%d%d", &X, &A, &B ); if ( X == 1 ) Add( A, B, 0 ), Add( B, A, 0 ); if ( X == 2 ) Add( A, B, 1 ); if ( X == 3 ) Add( B, A, 0 ); if ( X == 4 ) Add( B, A, 1 ); if ( X == 5 ) Add( A, B, 0 ); } for ( int i = 1; i <= N; ++i ) if ( !c[i] ) Tarjan(i); for ( int i = 1; i <= N; ++i ) for ( int j = hd[i]; j; j = nxt[j] ){ if ( c[i] != c[to[j]] ) Add( c[i], c[to[j]], val[j] ), in[c[to[j]]]++; else if ( val[j] ){ printf( "-1\n" ); return 0; } } topo(); LL ans(0); for ( int i = N + 1; i <= cnt; ++i ) f[i] = 1; for ( int i = 1; i <= sm; ++i ){ int t(o[i]); for ( int j = hd[t]; j; j = nxt[j] ) f[to[j]] = max( f[to[j]], f[t] + val[j] ); ans += 1ll * f[t] * s[t]; } printf( "%lld\n", ans ); return 0; }