• 洛谷5787 (线段树分治)


    例题:有一个 $n$个节点的图,在  $k$时间内有  $m$条边会出现后消失,要求出每一时间段内这个图是否是二分图。

    输入格式:第一行三个整数  $n, m, k$接下来 m行,每行四个整数   $x, y, l, r$,表示有一条连接  $x, y$的边在  $l$时刻出现  $r$时刻消失。

    输出格式:  $k$行,第  $i$行一个字符串 Yes 或 No,表示在第 i时间段内这个图是否是二分图

    分析:在时间轴上建一棵线段树,这样对于每个操作,相当于在线段树上进行区间操作。对于每条边,将它按照线段树区间操作的方式划分成  O(logk)段,用 vector 挂在线段树的节点上。遍历时,从根节点出发,每到一个节点,将挂在该节点上的所有边合并,然后递归处理左儿子和右儿子。如果发现有某条边合并会出现奇环,那么当前线段树节点所对应的时间区间都不会形成二分图。当到达叶子节点时,如果合并了所有挂在当前节点上的边,依旧满足二分图的性质,那么可以直接输出 Yes。回溯时,由于并查集不支持删边,我们可以使用可撤销并查集,即用一个栈记录下所有对并查集的操作。由于可撤销,因此不能路径压缩,为保证复杂度,必须按秩合并。

    #include<cstdio>
    #include<vector>
    #include<stack>
    #define fi first
    #define se second
    #define mid ((l + r) >> 1)
    using namespace std;
    const int N = 1e5 + 5;
    const int M = 2e5 + 5;
    
    typedef pair<int, int> pii;
    
    int n, m, k;
    int x[M], y[M], l[M], r[M], fa[N << 1], dep[N];
    vector<int> vt[N << 4];
    stack<pii> sta;
    
    int find(int u) { return u == fa[u] ? u : find(fa[u]); }
    inline void swap(int &x, int &y) { x ^= y ^= x ^= y; }
    
    void ins(int u, int l, int r, int cl, int cr, int id){
        if(cl <= l && cr >= r){
            vt[u].push_back(id);
            return ;
        }
        if(cl <= mid)  ins(u << 1, l, mid, cl, cr, id);
        if(cr > mid)  ins(u << 1 | 1, mid + 1, r, cl, cr, id);
    }
    
    void merge(int u, int v){
        if(dep[u] < dep[v])  swap(u, v);
        sta.push(make_pair(v, dep[u] == dep[v]));
        fa[v] = u,  dep[u] += (dep[u] == dep[v]);
    }
    
    void solve(int u, int l, int r){
        bool vis = 1;
        int siz = sta.size();
        for(auto &v : vt[u]){
            int k = find(x[v]), kk = find(y[v]);
            if(k == kk){
                vis = 0;
                for(int i = l; i <= r; ++i)  puts("No");
                break;
            }
            merge(find(x[v]), find(y[v] + N)),  merge(find(x[v] + N), find(y[v]));
        }
        if(vis){
            if(l == r)  puts("Yes");
            else{
                solve(u << 1, l, mid);
                solve(u << 1 | 1, mid + 1, r);
            }
        }
        while(sta.size() > siz){
            pii tt = sta.top();  sta.pop();
            dep[fa[tt.fi]] -= tt.second;
            fa[tt.fi] = tt.fi;
        }
    }
    
    int main(){
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= m; ++i)
            scanf("%d%d%d%d", &x[i], &y[i], &l[i], &r[i]);
        for(int i = 1; i <= n; ++i)  fa[i] = i, fa[i + N] = i + N;
        for(int i = 1; i <= m; ++i)  if(l[i] != r[i])  ins(1, 1, k, l[i] + 1, r[i], i);
        solve(1, 1, k);
        return 0;
    }
    你只有十分努力,才能看上去毫不费力。
  • 相关阅读:
    jquery 获取easyui combobox选中的值
    一个多余逗号引起的麻烦
    Microsoft.Office.Interop.Excel 放到B/S客户端失败问题 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 80070005 拒绝访问。
    自己收藏-javascript用window.open的子窗口关闭自己并且刷新父窗口
    easyUI datagrid 不刷新问题
    水晶报表中公式字段if else 语句无法正常执行的问题
    SQL SERVER 察看数据库连接池情况
    Data Table 转 List<Type>
    .Net 调用SAP RFC
    VS2017 插件介绍
  • 原文地址:https://www.cnblogs.com/214txdy/p/14024410.html
Copyright © 2020-2023  润新知