luoguP3250 [HNOI2016]网络 树链剖分 + 堆
机房某大佬告诉我,一条链在全局线段树中的区间最多有$log$段
因此同样的,代表不在这条链上的区间同样只有$log$段
对这$log$段区间进行维护即可
为了能够删除,在线段树的每个节点暴力维护一个堆
每次加入一条链时,在这$log$段区间上暴力加入元素
每次删除一条链时,暴力删除元素
询问时,对所有经过的区间进行查询
注意堆标记不要下传,直接标记永久化就行
插入 / 删除复杂度单次$O(\log^3 n)$
查询复杂度单次$O(log n)$
空间复杂度$O(n \log^2 n)$
注:$bzoj$会$MLE$....不要轻易尝试
注2:打了30多min,好累啊.....
注3:大家还是去学习$O(n \log n)$的优秀做法吧...
#include <map>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; extern inline char gc() {
static char RR[], *S = RR + , *T = RR + ;
if(S == T) fread(RR, , , stdin), S = RR;
return *S ++;
}
inline int read() {
int p = , w = ; char c = gc();
while(c > '' || c < '') { if(c == '-') w = -; c = gc(); }
while(c >= '' && c <= '') p = p * + c - '', c = gc();
return p * w;
} #define ri register int
#define sid 200050 int n, m, cnp, id;
int nxt[sid], node[sid], cap[sid]; inline void addedge(int u, int v) {
nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v;
nxt[++ cnp] = cap[v]; cap[v] = cnp; node[cnp] = u;
} int U[sid], V[sid], W[sid];
int dfn[sid], sz[sid], dep[sid];
int son[sid], anc[sid], fa[sid]; #define cur node[i]
void dfs(int o) {
sz[o] = ;
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o]) {
dep[cur] = dep[o] + ; fa[cur] = o; dfs(cur); sz[o] += sz[cur];
if(sz[cur] > sz[son[o]]) son[o] = cur;
}
} void dfs(int o, int ac) {
dfn[o] = ++ id; anc[o] = ac;
if(!son[o]) return; dfs(son[o], ac);
for(int i = cap[o]; i; i = nxt[i])
if(cur != fa[o] && cur != son[o]) dfs(cur, cur);
} struct Heap {
priority_queue <int> q1, q2;
inline void ins(int x) { q1.push(x); }
inline void era(int x) { q2.push(x); }
inline int top() {
while() {
if(q2.empty()) return q1.top();
if(q1.top() == q2.top()) q1.pop(), q2.pop();
else return q1.top();
}
}
} t[sid << ]; #define ls (o << 1)
#define rs (o << 1 | 1) void build(int o, int l, int r) {
t[o].ins(-); if(l == r) return;
int mid = (l + r) >> ;
build(ls, l, mid); build(rs, mid + , r);
} void upd(int o, int l, int r, int ml, int mr, int v, int opt) {
if(ml > mr) return;
if(ml > r || mr < l) return;
if(ml <= l && mr >= r) { if(opt) t[o].ins(v); else t[o].era(v); return; }
int mid = (l + r) >> ;
upd(ls, l, mid, ml, mr, v, opt);
upd(rs, mid + , r, ml, mr, v, opt);
} int qry(int o, int l, int r, int ml, int mr) {
if(ml > r || mr < l) return -;
if(ml <= l && mr >= r) return t[o].top();
int mid = (l + r) >> ;
return max(t[o].top(), max(qry(ls, l, mid, ml, mr), qry(rs, mid + , r, ml, mr)));
} struct Seg {
int l, r;
friend bool operator < (Seg a, Seg b)
{ return a.l < b.l; }
}; vector <Seg> re; void Upd(int u, int v, int w, int opt) {
re.clear();
int pu = anc[u], pv = anc[v];
while(pu != pv) {
if(dep[pu] < dep[pv]) swap(u, v), swap(pu, pv);
re.push_back( { dfn[pu], dfn[u] } );
u = fa[pu]; pu = anc[u];
}
if(dep[u] < dep[v]) swap(u, v);
re.push_back( { dfn[v], dfn[u] } );
re.push_back( { , } );
re.push_back( { n + , n + } );
sort(re.begin(), re.end());
for(ri i = ; i < re.size(); i ++)
upd(, , n, re[i - ].r + , re[i].l - , w, opt);
} int main() {
n = read(); m = read();
for(ri i = ; i < n; i ++) {
int u = read(), v = read();
addedge(u, v);
}
dfs(); dfs(, ); build(, , n);
for(ri i = ; i <= m; i ++) {
int opt = read(), u, v, w;
if(opt == ) {
u = read(); v = read(); w = read();
U[i] = u; V[i] = v; W[i] = w; Upd(u, v, w, );
}
if(opt == ) u = read(), Upd(U[u], V[u], W[u], );
if(opt == ) u = read(), printf("%d\n", qry(, , n, dfn[u], dfn[u]));
}
return ;
}
luoguP3250 [HNOI2016]网络 树链剖分 + 堆的更多相关文章
- BZOJ4538:[HNOI2016]网络(树链剖分,堆)
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
- [HNOI2016]网络 树链剖分,堆
[HNOI2016]网络 LG传送门 表示乱搞比正解难想. 整体二分很好想吧. 但是为了好写快乐,我们选择三个\(\log\)的乱搞. 先树剖,线段树套堆维护区间最大值.对于一次修改,如果是插入,就把 ...
- [HNOI2016]网络 [树链剖分,可删除堆]
考虑在 |不在| 这条链上的所有点上放上一个 \(x\),删除也是,然后用可删除堆就随便草掉了. // powered by c++11 // by Isaunoya #pragma GCC opti ...
- 【BZOJ4538】【HNOI2016】网络(树链剖分,线段树,堆)
题目链接,我是真的懒得调题目的格式... 题解 树链剖分搞一下LCA 把线段树弄出来 这只是形式上的线段树 本质上是维护一段区间的一个堆 每次把堆插入节点, 询问的时候查询线段树上的堆的最大值就行了 ...
- 2019.01.13 bzoj4538: [Hnoi2016]网络(树链剖分)
传送门 树链剖分一眼题. 题意简述: 给定一棵树,有三种操作: 加入一条路径 删除一条已加入的路径 询问不过一个点x的路径的最大值. 思路: 直接树链剖分维护答案. 因为询问的事不过点xxx的最大值, ...
- 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp
题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
- 焦作网络赛E-JiuYuanWantstoEat【树链剖分】【线段树】
You ye Jiu yuan is the daughter of the Great GOD Emancipator. And when she becomes an adult, she wil ...
- CF487E Tourists(圆方树+树链剖分+multiset/可删堆)
CF487E Tourists(圆方树+树链剖分+multiset/可删堆) Luogu 给出一个带点权的无向图,两种操作: 1.修改某点点权. 2.询问x到y之间简单路径能走过的点的最小点权. 题解 ...
- 2019 icpc南昌全国邀请赛-网络选拔赛J题 树链剖分+离线询问
链接:https://nanti.jisuanke.com/t/38229 题意: 给一棵树,多次查询,每次查询两点之间权值<=k的边个数 题解: 离线询问,树链剖分后bit维护有贡献的位置即可 ...
随机推荐
- C语言中的序列点
TAG: C, 序列点 DATE: 2013-08-07 序列点是程序执行序列中一些特殊的点. 当有序列点存在时,序列点前面的表达式必须求值完毕,并且副作用也已经发生, 才会计算序列点后面的表达式和其 ...
- Laravel 5.4 migrate时报错: Specified key was too long error
Laravel 5.4默认使用utf8mb4字符编码,而不是之前的utf8编码.因此运行php artisan migrate 会出现如下错误: [Illuminate\Database\QueryE ...
- HDU 2082 找单词 (普通母函数)
题目链接 Problem Description 假设有x1个字母A, x2个字母B,..... x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,..... 字母Z的价值为26.那么,对于 ...
- ThinkPHP自定义错误页面、成功页面及异常页面
为什么会选择 ThinkPHP 呢?首先,作为一款国产PHP框架,文档肯定比国外那些框架要丰富的多,而且容易看懂:其次,ThinkPHP已经发展了七八年的时间了,相对来说已经比较成熟了:当然,最重要的 ...
- AngularJS 指令绑定 & 简介
指令中独立scope 的 & 官方说明: 1. 绑定表达式 2. 经常用来绑定回调函数 诡异的地方在于,这个 & 某次听人说在子组件中是不能传值给callback的,好奇查了一下官方文 ...
- Ubuntu10.04 下安装RabbitVCS
安装RabbitVCS的方法步骤如下: 1.sudo add-apt-repository ppa:rabbitvcs/ppa #将rabbitvcs的添加到源里面.(次操作会提示是否要添 ...
- spring中的任务调度Quartz
Spring 整合 Quartz 任务调度 主要有两种方式. Quartz的官网:http://www.quartz-scheduler.org/ 这两种只是一些配置文件简单配置就OK了,但是根本无法 ...
- Springboot swagger2 导出api文档
具体导出的代码,参考了:http://www.spring4all.com/article/699 导出前,首先需要配置好swagger2,参见 https://www.cnblogs.com/yan ...
- NTP算法
网络时间协议 由特拉华大学的David L. Mills热心提供.http://www.eecis.udel.edu/~mills mills@udel.edu 由Reinhard v. Hanxle ...
- Effective C++学习进阶版
记得前段时间又一次拿起<Effective C++>的时候,有种豁然开朗的感觉,所以翻出了我第一遍读时做的笔记.只做参考以及查阅之用.如有需要请参阅<Effective C++> ...