像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

【题解】AGC056C 差分约束 思维 建模

好题,考察了对差分约束较深的理解。

首先限制区间 (l,r] 内恰好有 rl21,可以考虑将限制转化为前缀和数组上的限制,即 SrSl=rl2,又因为前缀和本身的限制关系 SiSi1[0,1],可以得出一个差分约束的关系:

{SrSl=rl2SiSi1+1Si1Si

直接将等于边拆成大于小于边做差分约束求字典序最小的 S,因为有负权边会被卡成 O(n2)

考虑将等号代表的关系使用一个代表元表示(Si=Sdel(i)+ci),这样可以避免掉上面的负权边,但是第二类边可能会出现 Si+ciSj+cj 移项得到 SiSj+cjcici>cj 时同样会出现负权边。

考虑如何避免负权边,之所以会出现负权边是因为第一类的传递关系中会涉及到量的改变,我们试图建立一种直接的等价类关系来描述第一类关系:

考虑式子拆开成一个左侧只和 l 相关右侧只和 r 相关的等式:2Srr=2Sll,这样我们就把传递关系改成了一种等价关系,定义 xi=2Sii,则上面三个式子分别变成了:

{xi=xjxixi1+1xi1xi+1

(当然还有 xixi1,这个条件会在后面的差分约束中天然被满足)

所以直接将所有第一种关系相同的 xi 用同一个变量 xdel(i) 表示,然后对所有代表变量解决差分约束问题。

同样的,我们只需要最小化 x 的字典序就可以最小化 S 的字典序,直接 bfs 跑差分约束即可,因为我们求的是字典序最小解,所以一定不会出现 xi=xi1 的情况,复杂度线性。

代码:(为方便使用了并查集进行缩等价类,复杂度会多一个 nα(n)

#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 ;
}
posted @   寂静的海底  阅读(12)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起