2019牛客暑期多校训练营(第八场)Flower Dance

2019牛客暑期多校训练营(第八场)Flower Dance
** 题意: ** 给 n n n个点 m m m条边,每条边有一个权值区间,表示能通过这个区间的 值的范围,问从 1 1 1 n n n可以通过的权值有多少个。
** 题解: **

1.DFS线段树+离散化+并查集

这个线段树,其实也不能算是个正常的线段树,他build 的之后就没啥用了,没有更新和查询.。。直接在线段树上dfs,首先把权值离散化,然后存入线段树中,线段树每个节点表示,区间[l,r],中有哪些边,这样每次深搜下去,经过的边用并查集维护起来,表示哪些点是联通的,然后如果,1n联通的话就更新权值。这题有回溯,就有拆边,所以并查集要保存路径,而且要加按秩合并的优化,不然会超时。
** 写离散化线段树尽量保存 (l,r] 左开右闭的区间值,保存[l,r] 的区间会出问题**

#include "bits/stdc++.h"

using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> P;
#define VNAME(value) (#value)
#define bug printf("*********\n");
#define debug(x) cout<<"["<<VNAME(x)<<" = "<<x<<"]"<<endl;
#define mid ((l + r) >> 1)
#define chl 2 * k + 1
#define chr 2 * k + 2
#define lson l, mid, chl
#define rson mid, r, chr
#define eb(x) emplace_back(x)
#define pb(x) emplace_back(x)
#define mem(a, b) memset(a, b, sizeof(a));

const LL mod = (LL) 1e9 + 7;
const int maxn = (int) 1e6 + 5;
const LL INF = 0x7fffffff;
const LL inf = 0x3f3f3f3f;
const double eps = 1e-8;

#ifndef ONLINE_JUDGE
clock_t prostart = clock();
#endif

void f() {
#ifndef ONLINE_JUDGE
    freopen("../data.in", "r", stdin);
#endif
}

//typedef __int128 LLL;

template<typename T>
void read(T &w) {//读入
    char c;
    while (!isdigit(c = getchar()));
    w = c & 15;
    while (isdigit(c = getchar()))
        w = w * 10 + (c & 15);
}

template<typename T>
void output(T x) {
    if (x < 0)
        putchar('-'), x = -x;
    int ss[55], sp = 0;
    do
        ss[++sp] = x % 10;
    while (x /= 10);
    while (sp)
        putchar(48 + ss[sp--]);
}

struct edge {
    int u, v, l, r;
} eg[maxn];


vector<int> v;

int get(int x) {
    return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

int n, m;
vector<int> dat[maxn];

void build(int l, int r, int k, int a, int b, int x) {
    if (l == a && b == r) {
        dat[k].emplace_back(x);
        return;
    }
    if (b <= mid) {
        build(lson, a, b, x);
    } else if (a >= mid) {
        build(rson, a, b, x);
    } else {
        build(lson, a, mid, x);
        build(rson, mid, b, x);
    }
}

vector<int> d[maxn];
int ans = 0;
int par[maxn];

int find(int x) {
    return (par[x] == x) ? x : find(par[x]);
}

int rk[maxn];

void unit(int x, int y, int dep) {
    x = find(x);
    y = find(y);
    if (x != y) {
        if (rk[x] < rk[y])swap(x, y);
        par[y] = x;
        d[dep].emplace_back(y);
        if (rk[x] == rk[y])rk[x]++;
    }
}

void dfs(int l, int r, int k, int dep) {
    d[dep].clear();
    for (auto au:dat[k]) {
        unit(eg[au].u, eg[au].v, dep);
    }
    if (find(1) == find(n)) {
        ans += v[r - 1] - v[l - 1];
    } else if (r != l + 1) {
        dfs(lson, dep + 1);
        dfs(rson, dep + 1);
    }
    for (auto au:d[dep]) {
        par[au] = au;
    }
}

int main() {
    f();
    read(n);
    read(m);
    for (int i = 0; i <= n; i++)par[i] = i;
    for (int i = 0; i < m; i++) {
        read(eg[i].u);
        read(eg[i].v);
        read(eg[i].l);
        read(eg[i].r);
        v.emplace_back(eg[i].l);
        v.emplace_back(eg[i].r + 1);
    }
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
    int mx = v.size();
    for (int i = 0; i < m; i++) {
        build(1, mx, 1, get(eg[i].l), get(eg[i].r + 1), i);
    }
    dfs(1, mx, 1, 0);
    output(ans);
    puts("");

#ifndef ONLINE_JUDGE
    cout << "运行时间:" << 1.0 * (clock() - prostart) / CLOCKS_PER_SEC << endl;
#endif
    return 0;
}

LCT+最小生成树 挖个坑,懒得学splay

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值