ICode9

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

CF1633E Spanning Tree Queries

2022-03-31 09:33:21  阅读:179  来源: 互联网

标签:CF1633E int 边权 Tree pos ++ vector Spanning id


CF1633E

原题链接 ←Click it

题目大意:给定一个无向带权图,现有\(k\)次询问,每次询问一个\(x\),对每次询问,边权的价值是\(|w_i-x|\),求出最小生成树的价值,最终的答案是对所有的询问结果取异或。

解题思路:我们先来回忆一下kruskal算法,先将所有边权升序排序,然后依次选边添加到集合中,可以发现如果每条边权的相对大小如果不发生变化,那么kruskal选的边不变。然后再来研究一下绝对值函数(没想到就是看起来这么简单的东西把我难倒了),Jozrd.png我们惊讶地发现,边权相对大小产生变化的地方只出现在两条直线的交点位置,边权斜率正负的改变只出现在与x轴的交点,那么我们的想法就非常简单了,我们将数轴按照这些交点切分,此时每一段区间的边权相对大小都不发生改变,我们求出每一段区间某个值的(为了方便,这里选择最右端的值,也就是交点的x值)最小生成树的价值,并统计生成树中边权斜率为正(或者为负)的数量。最后对每次询问都可以在\(O(log)\)的时间复杂度中求出(二分判断区间位置)。

参考代码:

int n, m;
struct Edge {
    int u, v, w;
};
vector<Edge> e;
struct DSU {
    int N;
    vector<int> pr;
    DSU(int n) : N(n) {
        pr.resize(N + 1);
        for(int i = 0; i <= N; i ++) {
            pr[i] = i;
        }
    }
    int root(int x) {
        return pr[x] == x ? x : pr[x] = root(pr[x]);
    }
    void unite(int x, int y) {
        int X = root(x), Y = root(y);
        if(X == Y) {
            return ;
        }
        pr[X] = Y;
    }
};
ll kruskal(int T, int &c) {
    //按照|w - T|排序,但是存在相等的情况要选w更小的,因为在交点左侧|w - T|更小
    sort(e.begin(), e.end(), [&] (const Edge &a, Edge &b) {
        if(abs(a.w - T) != abs(b.w - T))
            return abs(a.w - T) < abs(b.w -T);
        else 
            return a.w < b.w;
    });
    DSU dsu(n);
    int cnt = 0;
    ll res = 0;
    for(auto eg : e) {
        int A = dsu.root(eg.u), B = dsu.root(eg.v);
        if(A == B) continue;
        dsu.unite(A, B);
        cnt ++;
        if(eg.w - T < 0) c ++;
        res += abs(eg.w - T);
        if(cnt == n - 1) {
            break;
        }
    }
    return res;
}
void solve() {
    cin >> n >> m;
    for(int i = 0; i < m; i ++) {
        int u, v, w;
        cin >> u >> v >> w;
        e.push_back({u, v, w});
    }
    //定义了1e9为无穷
    vector<int> pos(1, 1e9);
    for(int i = 0; i < m; i ++) {
        for(int j = i; j < m; j ++) {
    //添加交点到pos
            pos.push_back(e[i].w + e[j].w >> 1);
        }
    }
    sort(pos.begin(), pos.end());
    //去重!
    pos.resize(unique(pos.begin(), pos.end()) - pos.begin());
    vector<ll> dis, cnr;
    for(auto T : pos) {
        int c = 0;
        dis.push_back(kruskal(T, c));
        cnr.push_back(c);
    }
    int p, k, a, b, c;
    cin >> p >> k >> a >> b >> c;
    vector<int> q(k);
    for(int i = 0; i < k; i ++) {
        if(i < p) {
            cin >> q[i];
        } else {
            q[i] = (1ll * q[i - 1] * a + b) % c;
        }
    }
    ll res = 0;
    for(int i = 0; i < k; i ++) {
        int id = lower_bound(pos.begin(), pos.end(), q[i]) - pos.begin();
        // 生成树价值偏移量的计算
        ll D = dis[id] - (cnr[id] * (pos[id] - q[i])) - (n - 1 - cnr[id]) * (q[i] - pos[id]);
        // cout << D << '\n';
        res ^= D;
    }
    cout << res << '\n';
}

标签:CF1633E,int,边权,Tree,pos,++,vector,Spanning,id
来源: https://www.cnblogs.com/Muly/p/16080257.html

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

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

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

ICode9版权所有