ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「CF319E」Ping-Pong「线段树」「并查集」

2019-10-21 19:00:40  阅读:301  来源: 互联网

标签:连边 CF319E log int 线段 查集 区间 Pong


题意

规定区间\((a,b)\)到区间\((c,d)\)有边当且仅当\(c<a<d\)或\(c<b<d\)。

起初区间集合为空。有\(n\)(\(n\leq 10^5\))次操作,每次操作形如:

  • \(1\) \(x\) \(y\)(\()|x|,|y|\leq10^9)\):加入一个新区间\((x,y)\),保证新区间长度最长

  • \(2\) \(x\) \(y\):询问第\(i\)个加入第区间能否到达第\(j\)个加入第区间,保证询问合法

题解

考虑连边的两种情况:第一种是包含,小的向大的连边;第二种是相交不包含,连双向边。

注意到答案最后不会走超过\(1\)条单向边,我们先考虑双向边。

由于是双向边,我们可以用并查集维护连通块。那对于一个新区间,我们得考虑它和哪些区间连双向边。

可以使用线段树来做这件事。把区间拆放到\(\log\)个线段树结点上。加新区间连边就把左右端点对应线段树叶子结点到根到路径上所有放的路径都合并掉,然后把标记改成自己。题目给了一个每次加入一个最长区间的限制,这样就保证了新区间不会被包含。复杂度也是对的,每个区间分\(\log\)段,每段加入一次删除一次。

询问就判是同个并查集,或者是包含关系就YES,否则NO。注意一个连通块要维护L和R用于判包含。

时间复杂度\(O(n\alpha(n)\log n)\)

#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
struct node {
    int op, l, r;
} a[N];
int q, n, b[N * 2], f[N], L[N], R[N];
inline bool bel(int u, int l, int r) {
    return l < u && u < r;
}
int find(int u) {
    return u == f[u] ? u : f[u] = find(f[u]);
}
vector<int> vec[N << 2];
void solve(int u, int l, int r, int p, int cur) {
    if(vec[u].size()) {
        for(int i = 0; i < (int) vec[u].size(); i ++) {
            int v = vec[u][i]; v = find(v); f[v] = cur;
            L[cur] = min(L[cur], L[v]); R[cur] = max(R[cur], R[v]);
        }
        vec[u].clear();
        vec[u].push_back(cur);
    }
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(p <= mid) solve(u << 1, l, mid, p, cur);
    else solve(u << 1 | 1, mid + 1, r, p, cur);
}
void pushe(int u, int l, int r, int ql, int qr, int cur) {
    if(l == ql && r == qr) {
        vec[u].push_back(cur);
        return ;
    }
    int mid = (l + r) >> 1;
    if(qr <= mid) pushe(u << 1, l, mid, ql, qr, cur);
    else if(ql > mid) pushe(u << 1 | 1, mid + 1, r, ql, qr, cur);
    else {
        pushe(u << 1, l, mid, ql, mid, cur);
        pushe(u << 1 | 1, mid + 1, r, mid + 1, qr, cur);
    }
}
int main() {
    scanf("%d", &q);
    for(int i = 1; i <= q; i ++) {
        scanf("%d%d%d", &a[i].op, &a[i].l, &a[i].r);
        if(a[i].op == 1) {
            b[++ n] = a[i].l; b[++ n] = a[i].r;
        }
    }
    sort(b + 1, b + n + 1);
    n = unique(b + 1, b + n + 1) - b - 1;
    int c = 0;
    for(int i = 1; i <= q; i ++) {
        if(a[i].op == 1) {
            a[i].l = lower_bound(b + 1, b + n + 1, a[i].l) - b;
            a[i].r = lower_bound(b + 1, b + n + 1, a[i].r) - b;
            c ++; f[c] = c; L[c] = a[i].l; R[c] = a[i].r;
            solve(1, 1, n, a[i].l, c);
            solve(1, 1, n, a[i].r, c);
            if(a[i].l < a[i].r - 1) {
                pushe(1, 1, n, a[i].l + 1, a[i].r - 1, c);
            }
        }
        if(a[i].op == 2) {
            int u = find(a[i].l), v = find(a[i].r);
            bool tag = u == v || bel(L[u], L[v], R[v]) || bel(R[u], L[v], R[v]);
            puts(tag ? "YES" : "NO");
        }
    }
    return 0;
}

标签:连边,CF319E,log,int,线段,查集,区间,Pong
来源: https://www.cnblogs.com/hongzy/p/11715314.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有