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维护有贡献的位置即可 ...
随机推荐
- weblogic 配置了ssl
jingyan.baidu.com/article/72ee561abfe531e16138dfb5.html http://blog.sina.com.cn/s/blog_7ffec3e201019 ...
- Python异常捕捉try except else finally有return时执行顺序探究
转载自 https://www.cnblogs.com/JohnABC/p/4065437.html 学习python或者其他有异常控制的编程语 言, 大家很有可能说try except finall ...
- Vue-Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象.当应用变得非常复杂时,store 对象就有可能变得相当臃肿. 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module) ...
- shell编程===执行shell脚本的四种方法
使用vim创建一个shell文件,命名 hello.sh #!/bin/bash echo "hello shell !" 在linux中进行加载 chmod +x ./hello ...
- c++动态规划dp算法题
问题1:找硬币,换钱的方法 输入: penny数组代表所有货币的面值,正数不重复 aim小于等于1000,代表要找的钱 输出:换钱的方法总数 解法1:经典dp,空间复杂度O(n*aim) class ...
- Qt跨线程调用错误解析及解决办法
错误提示:Error: Cannot create children for a parent that is in a different thread. 错误案例分析 新建SerialLink子线 ...
- Linux下不能挂载NTFS格式硬盘/U盘
如果大家以后在Ubuntu系统下面遇到NTFS格式的移动硬盘哪个分区不能挂载的话,可以尝试sudo ntfsfix /dev/你相应的分区
- WDCP各种停止重启命令
service wdapache start|stop|restart wdcp后台 启动|停止|重起service nginxd start|stop|restart nginx ...
- c++输出保留固定小数位数
cout<<setprecision(6)<<fixed<<ans<<endl;
- 使用情况查询top命令
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法. top - 01:06:48 up 1:22, 1 ...