大家都很强, 可与之共勉 。
这个标题是参考神犇LWD取的
题意:
n个人分糖,保证每个人都有糖,有k个限制条件,分别是a=b,a < b,a≥b,a > b,a≤b。这五种情况分别用x=1,2,3,4,5表示。求最少需要准备多少糖果。其中n,k≤10^6。
差分约束
顺便说一下差分约束,网上都讲得不详细。
一群知其然而不知其所以然的辣鸡
差分约束系统就是说的是满足一些带等号的不等式的一个系统。我们可以通过建立图论模型的方式求解。问的一般情况是最小值或者最大值是什么。
记住一个结论:
差分约束中求最小值用≥,跑最长路;求最大值用≤,跑最短路。
为什么这么做?
dis[u]表示的是u – s ( s为起点 ) 的最值。
那么如果是求最小值,所有的不等式都应该形如C < A – B, C为常数。然后B向A建立一条权值为C的边,dis [A] – dis [B] 最后就表示题目中的最值。henrongyixiang
题解
那么题中求的是最小值,就用 <= 然后化成C < A – B…
x=1即a=b,直接a→b,b→a权值都是0;
x=3即a≥b,直接b→a,权值为0;
x=5即a≤b,直接a→b,权值为0;
那么不带等号的怎么办呢?
(如果是实数可以不管,就是求得的最值取不到也在误差范围内。)
因为a,b均是整数,所以
x=2即a < b⇒a≤b−1,然后a→b,权值为1;
同理,x=4即a>b⇒a≥b+1,然后b→a,权值为1;
然后是与源点S连边。因为每个人都有糖,即dis[i]≥1⇒dis[i]−dis[S]≥1,所以S→i,权值为1。(直接放到队列里面就好了)
# include <bits/stdc++.h>
inline int readInt ( ) {
static char buf [1 << 18 | 1], *ss, *tt ;
# define pick( ) ( ( ss == tt ) ? ( tt = buf + fread ( ss = buf, 1, 1 << 18 | 1, stdin ), ( ss == tt ) ? -1 : *ss ++ ) : *ss ++ )
register int x, c ;
while ( ! isdigit ( c = pick ( ) ) ) ;
for ( x = -48 + c ; isdigit ( c = pick ( ) ) ; ( x *= 10 ) += c - 48 ) ;
# undef pick
return x ;
}
const int N = 1234567 ;
struct edge {
int to, w ;
edge* nxt ;
} g [N << 1], *NewEdge = g, *head [N] ;
inline int add_edge ( int u, int v, int w ) {
*( ++ NewEdge ) = ( edge ) { v, w, head [u] } ; head [u] = NewEdge ;
}
inline bool chkmax ( int& d, const int& x ) {
return ( d < x ) ? d = x, 1 : 0 ;
}
int dis [N] ;
int cnt [N] ;
std :: bitset < N > inq ;
std :: deque < int > Q ;
int main ( ) {
int n ( readInt ( ) ), k ( readInt ( ) ) ;
while ( k -- ) {
int x ( readInt ( ) ), a ( readInt ( ) ), b ( readInt ( ) ) ;
switch ( x ) {
case 1 : {
add_edge ( a, b, 0 ) ;
add_edge ( b, a, 0 ) ;
break ;
}
case 2 : {
if ( a == b ) return puts ( "-1" ), 0 ;
add_edge ( a, b, 1 ) ;
break ;
}
case 3 : {
add_edge ( b, a, 0 ) ;
break ;
}
case 4 : {
if ( a == b ) return puts ( "-1" ), 0 ;
add_edge ( b, a, 1 ) ;
break ;
}
case 5 : {
add_edge ( a, b, 0 ) ;
break ;
}
}
}
inq.reset ( ) ;
Q.push_front ( 1 ) ; dis [1] = 1 ; inq [1] = 1 ;
for ( register int i = 2 ; i <= n ; ++ i ) {
Q.push_back ( i ) ; // !!!
dis [i] = 1 ;
inq [i] = 1 ;
}
while ( ! Q.empty ( ) ) {
int u = Q.front ( ) ; Q.pop_front ( ) ;
inq [u] = 0 ;
for ( edge* it = head [u] ; it ; it = it -> nxt ) {
int v = it -> to ;
if ( chkmax ( dis [v], dis [u] + it -> w ) ) {
if ( ! inq [v] ) {
if ( ++ cnt [v] > n ) {
return puts ( "-1" ), 0 ;
}
( Q.empty ( ) || dis [Q.front ( )] < dis [v] ) ? Q.push_front ( v ) : Q.push_back ( v ) ;
inq [v] = 1 ;
}
}
}
}
long long ans ( 0 ) ;
for ( register int i = 1 ; i <= n ; ++ i ) ans += dis [i] ;
return std :: cout << ans << std :: endl, 0 ;
}