题目描述

给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树。(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在)

输入

第一行两个正整数N,M(N<=50000,M<=100000)表示原图的顶点数和边数。
下面M行,每行三个整数X,Y,W描述了图的一条边(X,Y),其边权为W(W<=10000)。保证两点之间至多只有一条边。
接着一行一个正整数Q,表示询问数。(1<=Q<=100000)
下面Q行,每行一个询问,询问中包含一个正整数T,表示把编号为T的边删掉(边从1到M按输入顺序编号)。

输出

Q行,对于每个询问输出对应最小生成树的边权和的值,如果图不连通则输出“Not connected”

样例输入

4 4
1 2 3
1 3 5
2 3 9
2 4 1
4
1
2
3
4

样例输出

15
13
9
Not connected


题解

最小生成树+树链剖分+线段树

首先考虑,不在最小生成树上的边,去掉后都可以选择最小生成树。

然后如果删掉在最小生成树上的边,那么去掉后,原有的树边一定不变,新添加的一定是能够构成一棵树的非树边。

于是先求出最小生成树,然后看每条非树边能够使多少条树边删去后连通。显然是树链上的边。

所以可以使用树链剖分+线段树的方法实现:使一条链上所有边权值对某值取min、查询某条边的权值。此时需要把边权放到深度更大的那个端点的点权上。

时间复杂度$O(n\log^2n)$,代码中使用了永久化标记。

注意:如果原图就是不连通的,那么每个询问的结果都应是“Not connected”。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
struct data
{
int x , y , z , id;
bool vis;
}a[N << 1];
int f[N] , head[N] , to[N << 1] , val[N << 1] , next[N << 1] , cnt , ref[N << 1] , fa[N] , deep[N] , si[N] , bl[N] , pos[N] , tot , mn[N << 2] , n;
bool cmp1(const data &a , const data &b)
{
return a.z < b.z;
}
bool cmp2(const data &a , const data &b)
{
return a.id < b.id;
}
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void dfs1(int x)
{
int i;
si[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x])
fa[to[i]] = x , deep[to[i]] = deep[x] + 1 , ref[val[i]] = to[i] , dfs1(to[i]) , si[x] += si[to[i]];
}
void dfs2(int x , int c)
{
int i , k = 0;
bl[x] = c , pos[x] = ++tot;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x] && si[to[i]] > si[k])
k = to[i];
if(k)
{
dfs2(k , c);
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x] && to[i] != k)
dfs2(to[i] , to[i]);
}
}
void update(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e)
{
mn[x] = min(mn[x] , a);
return;
}
int mid = (l + r) >> 1;
if(b <= mid) update(b , e , a , lson);
if(e > mid) update(b , e , a , rson);
}
int query(int p , int l , int r , int x)
{
if(l == r) return mn[x];
int mid = (l + r) >> 1;
if(p <= mid) return min(mn[x] , query(p , lson));
else return min(mn[x] , query(p , rson));
}
void modify(int x , int y , int v)
{
while(bl[x] != bl[y])
{
if(deep[bl[x]] < deep[bl[y]]) swap(x , y);
update(pos[bl[x]] , pos[x] , v , 1 , n , 1) , x = fa[bl[x]];
}
if(deep[x] > deep[y]) swap(x , y);
if(x != y) update(pos[x] + 1 , pos[y] , v , 1 , n , 1);
}
int main()
{
int m , q , i , sum = 0 , x , v , c = 0;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &a[i].x , &a[i].y , &a[i].z) , a[i].id = i;
sort(a + 1 , a + m + 1 , cmp1);
for(i = 1 ; i <= n ; i ++ ) f[i] = i;
for(i = 1 ; i <= m ; i ++ )
if(find(a[i].x) != find(a[i].y))
sum += a[i].z , a[i].vis = 1 , add(a[i].x , a[i].y , a[i].id) , add(a[i].y , a[i].x , a[i].id) , f[f[a[i].x]] = f[a[i].y] , c ++ ;
if(c < n - 1)
{
scanf("%d" , &q);
while(q -- ) puts("Not connected");
return 0;
}
dfs1(1) , dfs2(1 , 1);
memset(mn , 0x3f , sizeof(mn));
sort(a + 1 , a + m + 1 , cmp2);
for(i = 1 ; i <= m ; i ++ )
if(!a[i].vis)
modify(a[i].x , a[i].y , a[i].z);
scanf("%d" , &q);
while(q -- )
{
scanf("%d" , &x);
if(!a[x].vis) printf("%d\n" , sum);
else
{
v = query(pos[ref[x]] , 1 , n , 1);
if(v == 0x3f3f3f3f) puts("Not connected");
else printf("%d\n" , sum - a[x].z + v);
}
}
return 0;
}

【bzoj2238】Mst 最小生成树+树链剖分+线段树的更多相关文章

  1. 【Codeforces827D/CF827D】Best Edge Weight(最小生成树性质+倍增/树链剖分+线段树)

    题目 Codeforces827D 分析 倍增神题--(感谢T*C神犇给我讲qwq) 这道题需要考虑最小生成树的性质.首先随便求出一棵最小生成树,把树边和非树边分开处理. 首先,对于非树边\((u,v ...

  2. [HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]

    题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个 ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  4. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  5. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  6. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  7. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  8. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  9. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

随机推荐

  1. django中介模型,CBV模型,及logging日志配制

    1.中介模型 中介模型,这个是在我们创建表格时,多对多添加的时候应用到的,通过制定ManyToManyField字段中的through参数来定义,为两者的关系新建一个中介class 为什么会产生这个中 ...

  2. 前端JavaScript之DOM节点操作

    1.HTML DOM是啥 Document Object Model:定义了访问和操作HTML文档的标准方法,把HTML文档呈现为带有元素,属性和文本的树状结构 2.解析过程 HTML加载完毕,渲染引 ...

  3. 微信H5单页面滑动的时候如何避免出界,出现头部和底部的黑底?

    ios系统微信浏览器.safari浏览器中h5页面上拉下滑导致悬浮层脱离窗口的解决方法 ios偶现下拉出现黑底时,界面第一次上拉时拉不动的解决方案: document.querySelector('# ...

  4. 6.安装使用vue-quill-editor

    前言: 在vue项目中,因为涉及到使用文本编辑器, 恰恰vue-quill-editor就是一个简单实用的富文本编辑器. 参考文档:vue中使用vue-quill-editor富文本编辑器,自定义to ...

  5. 03-UI控件浏览

    UI控件浏览 可能用得上的UI控件 为了便于开发者打造各式各样的优秀app,UIKit框架提供了非常多功能强大又易用的UI控件 下面列举一些在开发中可能用得上的UI控件(红色表明最常用,蓝色代表一般, ...

  6. 深入浅出:了解JavaScript的ES6、ES7新特性

    参照阮一峰博客:http://es6.ruanyifeng.com/#README es6常见题:https://blog.csdn.net/qq_39207948/article/details/8 ...

  7. spring-mybatis整合异常2

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' ...

  8. 死锁-Java代码示例

    class MyThread implements Runnable{ private Object o1 = new Object(); private Object o2 = new Object ...

  9. PHP ping

    <?php /// start ping.inc.php /// $g_icmp_error = "No Error"; // timeout in ms function ...

  10. Git使用简单总结--源自廖雪峰网站

    创建版本库git add加入到暂存区git commit -m" "加入到分支 时光机穿梭git satus查看仓库的当前状态git diff file 查看修改内容 版本回退HE ...