【bzoj2238】Mst 最小生成树+树链剖分+线段树
题目描述
输入
输出
样例输入
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 最小生成树+树链剖分+线段树的更多相关文章
- 【Codeforces827D/CF827D】Best Edge Weight(最小生成树性质+倍增/树链剖分+线段树)
题目 Codeforces827D 分析 倍增神题--(感谢T*C神犇给我讲qwq) 这道题需要考虑最小生成树的性质.首先随便求出一棵最小生成树,把树边和非树边分开处理. 首先,对于非树边\((u,v ...
- [HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]
题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- 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 ...
随机推荐
- 深入浅出:了解JavaScript中的call,apply,bind的差别
在 javascript之 this 关键字详解文章中,谈及了如下内容,做一个简单的回顾: 1.this对象的涵义就是指向当前对象中的属性和方法. 2.this指向的可变 ...
- 关于使用js下载图片
使用js进行图片下载是很常见的需求,但是解决起来却不是那么顺利. 服务器返回了一个图片地址,网上一搜基本都是用a标签的download属性,但是兼容性实在是很差.这里推荐使用blob. 上代码: va ...
- Delphi的Edit控件中只能输入数字且只能输入一个小数点
使用这种功能必须使用 OnKeyPress 事件,该事件是在窗体中获得键盘输入的焦点,并且在用户按键时发生.OnKeyPress 事件中有个重要参数:Key.Key 参数为Char 型,它能够获得用户 ...
- jstree 全部选中事件 select_all 使用
select_all function of jstree not checked node for jstree-open branch of ajax-jstree 很尴尬啊,找了整个百度,360 ...
- 【PHP基础】序列化serialize()与反序列化unserialize()
序列化serialize()与反序列化unserialize(): 序列化serialize():就是将一个变量所代表的 “内存数据”转换为“字符串”的形式,并持久保存在硬盘(写入文件中保存)上的一种 ...
- C# 设置窗口大小为不可调、取消最大化、最小化窗口按键
this.FormBorderStyle = FormBorderStyle.FixedDialog;//设置边框为不可调节 this.MaximizeBox = false; //取消最大化按键 t ...
- python——字符串的操作判断
s为字符串 s.isalnum() 所有字符都是数字或者字母,为真返回 Ture,否则返回 False. s.isalpha() 所有字符都是字母,为真返回 Ture,否则返回 False. s ...
- 笔记-python-redis接口
笔记-python-redis接口 1. python 与redis接口 redis是redis数据库的python接口包,为python提供的redis的调用接口. 注:文档内容主要基于h ...
- IIS发布错误记录
1.HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效. 详细错误信息模块 IIS Web Core 通知 BeginRequ ...
- Android面试收集录17 Android进程优先级
在安卓系统中:当系统内存不足时,Android系统将根据进程的优先级选择杀死一些不太重要的进程,优先级低的先杀死.进程优先级从高到低如下. 前台进程 处于正在与用户交互的activity 与前台act ...