BZOJ2001 [Hnoi2010]City 城市建设 【CDQ分治 + kruskal】

题目链接

BZOJ2001

题解

CDQ分治神题。。。

难想难写。。

比较朴素的思想是对于每个询问都求一遍\(BST\),这样做显然会爆

考虑一下时间都浪费在了什么地方

我们每次求\(BST\)实际上就只有一条边不同,我们实际浪费了很多时间在处理相同的边上

那就考虑分治

对于一个待修改的边集,我们将其权值全部设为\(-\infty\),跑一遍\(BST\),此时其它边如果被选中,说明这些边在单独询问时也一定会被选,将这些边连的点缩点

同样,对于一个待修改的边集,我们将其权值全部设为\(\infty\),跑一遍\(BST\),此时其它边没被选中,说明这些边在单独询问时也一定不会被选,将这些边删掉

这样就可以\(A\)了

复杂度我也不知道是什么

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 50005,maxm = 50005,INF = 0x3fffffff;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
struct EDGE{int i,a,b,w;}e[50][maxm],d[maxm],b[maxm];
struct Que{int u,v;}q[maxm];
inline bool operator <(const EDGE& a,const EDGE& b){
    return a.w < b.w;
}
LL ans[maxm];
int n,m,Q,sum[50],w[maxm],id[maxm],a[maxm];
int pre[maxm];
int find(int u){return u == pre[u] ? u : pre[u] = find(pre[u]);}
void clear(int t){
    for (int i = 1; i <= t; i++){
        pre[d[i].a] = d[i].a;
        pre[d[i].b] = d[i].b;
    }
}
void comb(int& t,LL& Ans){
    clear(t); int tmp = 0,fa,fb;
    sort(d + 1,d + 1 + t);
    REP(i,t){
        fa = find(d[i].a); fb = find(d[i].b);
        if (fa != fb){
            pre[fb] = fa;
            b[++tmp] = d[i];
        }
    }
    REP(i,tmp) {
        pre[b[i].a] = b[i].a;
        pre[b[i].b] = b[i].b;
    }
    REP(i,tmp) if (b[i].w != -INF){
        fa = find(b[i].a); fb = find(b[i].b);
        if (fa != fb){
            pre[fb] = fa;
            Ans += b[i].w;
        }
    }
    tmp = 0;
    REP(i,t){
        fa = find(d[i].a); fb = find(d[i].b);
        if (fa != fb){
            b[++tmp] = d[i];
            id[d[i].i] = tmp;
            b[tmp].a = find(b[tmp].a);
            b[tmp].b = find(b[tmp].b);
        }
    }
    REP(i,tmp) d[i] = b[i];
    t = tmp;
}
void rd(int& t){
    clear(t); int tmp = 0,fa,fb;
    sort(d + 1,d + 1 + t);
    REP(i,t){
        fa = find(d[i].a); fb = find(d[i].b);
        if (fa != fb){
            pre[fb] = fa;
            b[++tmp] = d[i];
        }
        else if (d[i].w == INF){
            b[++tmp] = d[i];
        }
    }
    for (int i = 1; i <= tmp; i++) d[i] = b[i];
    t = tmp;
}
void solve(int l,int r,int now,LL Ans){
    int t = sum[now];
    if (l == r) a[q[l].u] = q[l].v;   //原标号边权值
    for (int i = 1; i <= t; i++)
        e[now][i].w = a[e[now][i].i];  //边赋值
    for (int i = 1; i <= t; i++)
        d[i] = e[now][i],id[d[i].i] = i;  //新边对应旧边位置
    if (l == r){
        ans[l] = Ans; clear(t);
        sort(d + 1,d + 1 + t);
        int fa,fb;
        for (int i = 1; i <= t; i++){
            fa = find(d[i].a); fb = find(d[i].b);
            if (fa != fb){
                pre[fb] = fa; ans[l] += d[i].w;
            }
        }
        return;
    }
    for (int i = l; i <= r; i++) d[id[q[i].u]].w = -INF;
    comb(t,Ans);
    for (int i = l; i <= r; i++) d[id[q[i].u]].w = INF;
    rd(t);
    REP(i,t) e[now + 1][i] = d[i];
    sum[now + 1] = t;
    int mid = l + r >> 1;
    solve(l,mid,now + 1,Ans);
    solve(mid + 1,r,now + 1,Ans);
}
int main(){
    n = read(); m = read(); Q = read();
    for (int i = 1; i <= m; i++){
        e[0][i].i = i;
        e[0][i].a = read();
        e[0][i].b = read();
        a[i] = e[0][i].w = read();
    }
    for (int i = 1; i <= Q; i++){
        q[i].u = read();
        q[i].v = read();
    }
    sum[0] = m;
    solve(1,Q,0,0);
    for (int i = 1; i <= Q; i++)
        printf("%lld\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/9065839.html

时间: 2024-09-30 05:45:06

BZOJ2001 [Hnoi2010]City 城市建设 【CDQ分治 + kruskal】的相关文章

[bzoj2001][Hnoi2010][City 城市建设] (cdq分治)

Description PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁.Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费.Louis希望建造最少的道路使得国内所有的城市连通.但是由于某些因素,城市之间修建道路需要的花费会随着时间而改变,Louis会不断得到某道路的修建代价改变的消息,他希望每得到一条消息后能立即知道使城市连通的最小花费总和, Louis决定求助于你来完成这个任务. Input 文件第一行包含三个整数N,M,Q,分别表示城市的

BZOJ2001 [Hnoi2010]City 城市建设

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作.   本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目链接:BZOJ2001 正解:CDQ分治+并查集 解题报告: 这道题的$CDQ$分治思想非常巧妙- 考虑我在处理区间$[l,r]$时的情况,我把在这一段区间中会被修改的边称为特殊边, 我先把特殊边的权值设为$-inf$,跑一遍$MST$,此时在$M

【HNOI2010】【BZOJ2001】City 城市建设

Description PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁.Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费.Louis希望建造最少的道路使得国内所有的城市连通.但是由于某些因素,城市之间修建道路需要的花费会随着时间而改变,Louis会不断得到某道路的修建代价改变的消息,他希望每得到一条消息后能立即知道使城市连通的最小花费总和, Louis决定求助于你来完成这个任务. Input 文件第一行包含三个整数N,M,Q,分别表示城市的

【bzoj2001】 Hnoi2010—City 城市建设

http://www.lydsy.com/JudgeOnline/problem.php?id=2001 (题目链接) 题意 给出一张无向图,$m$组操作,每次修改一条边的权值,对于每次操作输出修改之后的图的最小生成树边权和. Solution nnd开了半个小时的脑洞,然并卵.感谢这位大爷的代码与题解:http://blog.csdn.net/u013368721/article/details/39183033 我们对时间cdq分治,如何在每一层向下递归的时候减小问题规模呢,两个关键的操作:

BZOJ-2001-city城市建设-HNOI2010-CDQ分治

描述 给出有n个点, m条边的无向图, 每次修改一条边的权值, 求修改后的最小生成树的大小. 修改次数 ≤ 50000. 分析 还是CDQ分治, 但是有点特殊. 目前的CDQ分治还是停留在看题解看别人代码才理解的层面. 有一些边一定在部分修改后的最小生成树中, 这是优化的中心思想吧. 然后一个减少边的操作, 一个减少点的操作. 看课件吧. 减少点的方法是缩点, 用并查集. 一开始想用全局变量d, n, m, ans代替函数参数传递. 后来发现因为分治的缘故这样做是不行的. 代码

bzoj-2001 City 城市建设

题意: 给出一个n个结点m条边的带权无向连通图,有q次操作: 每次操作是修改一个边的权值,要求每次操作后输出这个图中最小生成树的权值和: n<=20000,m<=50000,q<=50000: 题解: 网上题解都是那些鬼畜的分治做法,每层求最小生成树将问题缩小到可以接受的范围: 不过那个方法不好理解并且难以推广,所以wyfcyx大爷提出了一种更加让人愉悦的做法: 首先这个问题不能直接用LCT维护,因为当删去一条边(边的权值变大)之后,我们无法知道这两个连通块之间是否还有更小边相连: 也就

【bzoj3672】[Noi2014]购票 斜率优化+CDQ分治+树的点分治

题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费的最小代价(中途可以经停其它点) 输入 第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到).输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市.其中第 v 行包含 5 个非负整数 $f_v,s_v,p_v,q_v,l_v$,分别表示城市 v 的父亲城市,它到

【BZOJ3456】【CDQ分治+FNT】城市规划

试题来源 2013中国国家集训队第二次作业 问题描述 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案. 好了, 这就是困扰阿狸的问题.

CDQ分治与整体二分小结

前言 这是一波强行总结. 下面是一波瞎比比. 这几天做了几道CDQ/整体二分,感觉自己做题速度好慢啊. 很多很显然的东西都看不出来 分治分不出来 打不出来 调不对 上午下午晚上的效率完全不一样啊. 完蛋.jpg 绝望.jpg. 关于CDQ分治 CDQ分治,求的是三维偏序问题都知道的. 求法呢,就是在分治外面先把一维变成有序 然后分治下去,左边(l,mid)关于右边(mid+1,r)就不存在某一维的逆序了,所以只有两维偏序了. 这个时候来一波"树状数组求逆序对"的操作搞一下二维偏序 就可