【题解】AGC056C 差分约束 思维 建模
好题,考察了对差分约束较深的理解。
首先限制区间
直接将等于边拆成大于小于边做差分约束求字典序最小的
考虑将等号代表的关系使用一个代表元表示(
考虑如何避免负权边,之所以会出现负权边是因为第一类的传递关系中会涉及到量的改变,我们试图建立一种直接的等价类关系来描述第一类关系:
考虑式子拆开成一个左侧只和
(当然还有
所以直接将所有第一种关系相同的
同样的,我们只需要最小化
接下来我们来证明使用差分约束系统构造出的解天然满足
代码:(为方便使用了并查集进行缩等价类,复杂度会多一个
#include<bits/stdc++.h>
#define ll long long
#define all(x) x.begin(),x.end()
#define rep(i,x,y) for(auto i(x);i<=(y);++i)
#define Rep(i,x,y) for(auto i(x);i>=(y);--i)
using namespace std;
const int N = 1e6 + 20 ;
int n , m , x[N] , fa[N] , ptr ;
vector <int> ed[N] ;
inline int find (int x) {
while (x ^ fa[x]) x = fa[x] = fa[fa[x]] ;
return x;
}
signed main ( ) {
ios :: sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
cin >> n >> m ; iota (fa,fa+n+1,0);
rep (i,1,m) {
int l , r ; cin >> l >> r ; -- l ;
int gl = find (l) , gr = find (r) ;
if(fa[gl] ^ gr) fa[gl] = gr ;
}
rep (i,1,n) {
ed[find(i)].emplace_back (find(i - 1)) ;
ed[find(i - 1)].emplace_back (find(i)) ;
}
memset(x,-1,sizeof x); x[find(0)] = 0;
vector <int> q = {find(0)} ;
while (ptr < (int)q.size( )) {
int u = q[ptr ++];
for (int v : ed[u]) {
if (!~x[v]) {
x[v] = x[u] + 1 ;
q.emplace_back(v) ;
}
}
}
rep (i,1,n)
if (x[find(i)] > x[find(i - 1)])
cout << 0 ;
else
cout << 1 ;
return 0 ;
}