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;
}

 

posted @ 2018-08-30 14:03  remoon  阅读(164)  评论(0编辑  收藏  举报