首页 > 其他分享 >【题解】P5787 二分图 /【模板】线段树分治

【题解】P5787 二分图 /【模板】线段树分治

时间:2023-01-22 20:24:58浏览次数:76  
标签:sz P5787 log int 题解 线段 DSU mid 模板

概念

线段树分治是一种用于维护时间轴等的离线算法,本质上是通过维护时间轴的连续区间得到某一时刻的状态。

时间复杂度和普通线段树相同,空间复杂度为 \(O(n \log n)\)

例题

P5787 二分图 /【模板】线段树分治

将每条边看成修改操作,则它的作用范围是时刻区间 \([l, r)\).

考虑对时间轴构造一棵线段树。对于线段树上的结点,假设它代表的区间是 \([l, r]\),则该结点维护所有在 \([l, r]\) 时刻均存在的边。

于是从根到叶结点的路径可以维护某一时刻存在的所有边。

假如可以快速判定二分图,我们只需要对整棵线段树进行一次遍历,动态维护当前的图就行。

判定二分图可以考虑可撤销扩展域并查集。

因为线段树树高为 \(O(\log n)\) 级别,所以每条边至多被分解成 \(O(\log n)\) 个信息,空间复杂度为 \(O(m \log n)\).

复杂度为 \(O(k \log k \log n)\)

代码

#include <cstdio>
#include <vector>
using namespace std;

const int maxn = 1e5 + 5;
const int maxk = 1e5 + 5;
const int dsu_sz = maxn << 1;
const int t_sz = maxk << 2;

typedef pair<int, int> pii;

#define pb push_back
#define mp make_pair
#define swap(x, y) x ^= y ^= x ^= y

int n, m, k;
bool ans[maxk];

namespace DSU
{
    int top, stk[dsu_sz], fa[dsu_sz], sz[dsu_sz];

    void init() { for (int i = 1; i <= (n << 1); i++) fa[i] = i, sz[i] = 1; }

    int get(int x) { return (fa[x] == x ? x : get(fa[x])); }

    void merge(int x, int y)
    {
        x = get(x), y = get(y);
        if (x == y) return;
        if (sz[x] > sz[y]) swap(x, y);
        fa[x] = y, sz[y] += sz[x], stk[++top] = x;
    }

    void undo(int lst)
    {
        while (top > lst)
        {
            int u = stk[top--];
            sz[fa[u]] -= sz[u], fa[u] = u;
        }
    }
}

namespace SGT
{
    #define ls (k << 1)
    #define rs (k << 1 | 1)

    vector<pii> edge[t_sz];

    void update(int k, int l, int r, int ql, int qr, int u, int v)
    {
        if ((l >= ql) && (r <= qr)) return edge[k].pb(mp(u, v)), void();
        int mid = (l + r) >> 1;
        if (ql <= mid) update(ls, l, mid, ql, qr, u, v);
        if (qr > mid) update(rs, mid + 1, r, ql, qr, u, v);
    }

    void query(int k, int l, int r)
    {
        int lst = DSU::top;
        for (pii it : edge[k])
        {
            int u = it.first, v = it.second;
            DSU::merge(u, v + n), DSU::merge(v, u + n);
            if ((DSU::get(u) == DSU::get(u + n)) || (DSU::get(v) == DSU::get(v + n))) return DSU::undo(lst), void();
        }
        if (l == r) ans[l] = true;
        else
        {
            int mid = (l + r) >> 1;
            query(ls, l, mid), query(rs, mid + 1, r);
        }
        DSU::undo(lst);
    }
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    DSU::init();
    for (int i = 1, u, v, l, r; i <= m; i++)
    {
        scanf("%d%d%d%d", &u, &v, &l, &r);
        if (l != r) SGT::update(1, 1, k, l + 1, r, u, v);
    }
    SGT::query(1, 1, k);
    for (int i = 1; i <= k; i++) puts(ans[i] ? "Yes" : "No");
    return 0;
}

标签:sz,P5787,log,int,题解,线段,DSU,mid,模板
From: https://www.cnblogs.com/lingspace/p/xian-duan-shu-fen-zhi.html

相关文章

  • Codeforces Round #845 (Div. 2) D题解
    D.ScoreofaTree题目链接:https://codeforces.com/contest/1777/problem/D个人感觉还是比较简单的一道计数题题意是给你一颗有n(n<=2e5)节点的树,初始时每个节点有一个......
  • 【题解】P4755 Beautiful Pair
    麻了,这么多典题没做过……思路分治/笛卡尔树。这一类和区间最值相关的区间端点对计数应该都可以用这种做法做。由于求的是最大值,不妨从大到小考虑每个\(a_i\)的贡......
  • 【题解】Codeforces Round #845 (Div. 2) and ByteRace 2023
    建议开题顺序:A->B->C->F->E->D诈骗差评,典题差评,想易写难数据结构差评。A.EverybodyLikesGoodArrays!好像是结论题,但是一力降十会。显然最后合并完后,每个......
  • P5030 题解
    前言题目传送门!更好的阅读体验?一道没啥意思的题目,但是好像很多题解都过不了现在的数据?思路只不过是把正常题目的马(\(1,2\))换成了另一种东西(\(1,3\))。很套路地,黑白......
  • 洛谷 P1123 取数游戏 (又是写了好久 最后还是无奈看了题解……)
    对于这个题感觉是一个比较典型的dfs.本题的状态是对于每个数字你可以选也可以不选,但是一旦你选定某个数字之后,他会对其周围的数字产生影响所以一定要标记好(注意这里标记的......
  • AT_abc286d 题解
    板子首先我们看到值域并不大。因此可以维护值域,跑完全背包。具体而言维护某一个值(小于\(10000\))是否能被凑出来,然后枚举物品种类以及物品数量即可。一般而言,完全背包......
  • AT_abc286e 题解
    首先观察到\(n\leq300\)加上全源“最短路”便可以自然而然的想到floyd。注意到floyd算法的可行性只依赖统计的东西具有优先级。这里我们定义优先级为最短路最短且......
  • ABC286 A-E题解
    题目虽然是大年三十,但是玩手机没写题有意思。从50分钟才开始看题。A题意:将数组中\([p,q]\)与\([r,s]\)的元素交换并输出。sbt。B大意:将字符中的na换成nya。......
  • AcWing 第87场周赛题解
    T1移动棋子算出为\(1\)的点离\((3,3)\)的距离即可。#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;intmain(){int......
  • LeetCode.面试题02.05-链表求和-题解分析
    题目来源面试题02.05.链表求和题目详情给定两个用链表表示的整数,每个节点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并......