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[23456], *S = RR + 23333, *T = RR + 23333; if(S == T) fread(RR, 1, 23333, stdin), S = RR; return *S ++; } inline int read() { int p = 0, w = 1; char c = gc(); while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); } while(c >= '0' && c <= '9') p = p * 10 + c - '0', 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] = 1; for(int i = cap[o]; i; i = nxt[i]) if(cur != fa[o]) { dep[cur] = dep[o] + 1; 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(1) { if(q2.empty()) return q1.top(); if(q1.top() == q2.top()) q1.pop(), q2.pop(); else return q1.top(); } } } t[sid << 1]; #define ls (o << 1) #define rs (o << 1 | 1) void build(int o, int l, int r) { t[o].ins(-1); if(l == r) return; int mid = (l + r) >> 1; build(ls, l, mid); build(rs, mid + 1, 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) >> 1; upd(ls, l, mid, ml, mr, v, opt); upd(rs, mid + 1, r, ml, mr, v, opt); } int qry(int o, int l, int r, int ml, int mr) { if(ml > r || mr < l) return -1; if(ml <= l && mr >= r) return t[o].top(); int mid = (l + r) >> 1; return max(t[o].top(), max(qry(ls, l, mid, ml, mr), qry(rs, mid + 1, 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( { 0, 0 } ); re.push_back( { n + 1, n + 1 } ); sort(re.begin(), re.end()); for(ri i = 1; i < re.size(); i ++) upd(1, 1, n, re[i - 1].r + 1, re[i].l - 1, w, opt); } int main() { n = read(); m = read(); for(ri i = 1; i < n; i ++) { int u = read(), v = read(); addedge(u, v); } dfs(1); dfs(1, 1); build(1, 1, n); for(ri i = 1; i <= m; i ++) { int opt = read(), u, v, w; if(opt == 0) { u = read(); v = read(); w = read(); U[i] = u; V[i] = v; W[i] = w; Upd(u, v, w, 1); } if(opt == 1) u = read(), Upd(U[u], V[u], W[u], 0); if(opt == 2) u = read(), printf("%d\n", qry(1, 1, n, dfn[u], dfn[u])); } return 0; }
喵喵喵?喵喵喵! 喵喵喵......