luoguP4175 CTSC2008网络管理

一句话题意:树上路径带修第k大

考虑树上不带修第k大怎么做的:
维护一个前缀主席树,然后\(u\), \(v\), \(LCA(u, v)\)\(fa[LCA(u, v)]\)四个主席树相减即可

这题这么做就会出现一个问题
就是如果修改u的线段树的值,那么所有位于u的子树的线段树都要进行修改
如何高效修改子树内的线段树呢
想到了\(dfs\)
一个子树在dfs序上面是一个连续的区间
那么如果我们把前缀主席树差分一下
(实际上就是变成了每个节点单独一个动态开点线段树)
然后子树修改就转化成了区间修改,区间修改又转化成了单点修改

那么如何查询呢
我们还是需要把u到根的路径上的线段树全部加起来
求前缀? 树状数组?
但是我们发现如果树状数组维护的是u到根的路径上的线段树,不好处理
只能类似倍增LCA的方法

可不可以有更好的方法?
我们发现,如果树状数组直接在dfs序上维护前缀会很好写
并且dfs序还有一个性质
就是对于u和他的一个祖先x
\(dfn[x]\)\(dfn[u]\) 这一段就是x到u这条路径
\(sum[x]\)表示dfs序上1至x的点的权值前缀和
那么\(sum[dfn[u]] - sum[dfn[u]]\)就是u到x这条链上的点权和
因为除了u到x的链以外的部分都相同,抵消了

所以这题也是同理
用树状数组维护一下dfs序的对应节点的线段树的前缀和即可

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 200000 + 10;
const int INF = 0x3f3f3f3f;
#define lowbit(x) ((x) & (-(x)))
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], ind;
inline void add_edge(int u, int v){
    nxt[++ ind] = head[u]; head[u] = ind; to[ind] = v;
}
int n, q, a[MAXN], arr[MAXN], len;
struct Q{
    int k, a, b;
}query[MAXN];
inline void init(void){
    scanf("%d%d", &n, &q);
    int cnt = 0;
    for(register int i = 1; i <= n; ++ i)
        scanf("%d", &a[i]), arr[ ++ cnt] = a[i];
    int u, v;
    for(register int i = 1; i < n; ++ i){
        scanf("%d%d", &u, &v);
        add_edge(u, v); add_edge(v, u);
    }
    for(register int i = 1; i <= q; ++ i){
        scanf("%d%d%d", &query[i].k, &query[i].a, &query[i].b);
        if(query[i].k == 0) arr[++ cnt] = query[i].b;
    }
    sort(arr + 1, arr + cnt + 1);
    len = unique(arr + 1, arr + cnt + 1) - arr - 1;
}
int ls[MAXN * 400], rs[MAXN * 400], w[MAXN * 400], root[MAXN];
int fa[MAXN], son[MAXN], siz[MAXN], depth[MAXN], Top[MAXN], dfn[MAXN], dfs_clock;
int tot;
void modify(int &node, int l, int r, int pos, int val){
    if(!node) node = ++ tot;
    w[node] += val;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(pos <= mid) modify(ls[node], l, mid, pos, val);
    else modify(rs[node], mid + 1, r, pos, val);
}
void lowbitModify(int x, int pos, int val){
    for(register int i = x; i <= n; i += lowbit(i)) 
        modify(root[i], 1, len, pos, val);
}
void dfs1(int node, int fath){
    dfn[node] = ++ dfs_clock;
    fa[node] = fath; siz[node] = 1; depth[node] = depth[fath] + 1;
    for(register int i = head[node]; i; i = nxt[i]){
        int j = to[i]; if(j == fath) continue;
        dfs1(j, node);
        siz[node] += siz[j];
        if(siz[son[node]] < siz[j]) son[node] = j;
    }
}
void dfs2(int node, int topn){
    Top[node] = topn; 
    if(son[node]) dfs2(son[node], topn);
    for(register int i = head[node]; i; i = nxt[i]){
        int j = to[i]; if(j == son[node] || j == fa[node]) continue;
        dfs2(j, j);
    }
}
inline int LCA(int u, int v){
    while(Top[u] != Top[v]){
        if(depth[Top[u]] < depth[Top[v]]) swap(u, v);
        u = fa[Top[u]];
    }
    if(depth[u] > depth[v]) swap(u, v);
    return u;
}
int tmp[2][MAXN];
int Query(int l, int r, int k){
    if(l == r) return l;
    int mid = (l + r) >> 1;
    int sum = 0;
    for(register int i = 1; i <= tmp[1][0]; ++ i) sum += w[rs[tmp[1][i]]];
    for(register int i = 1; i <= tmp[0][0]; ++ i) sum -= w[rs[tmp[0][i]]];
    if(k <= sum){
        for(register int i = 1; i <= tmp[1][0]; ++ i) tmp[1][i] = rs[tmp[1][i]];
        for(register int i = 1; i <= tmp[0][0]; ++ i) tmp[0][i] = rs[tmp[0][i]];
        return Query(mid + 1, r, k);
    }
    else{
        for(register int i = 1; i <= tmp[1][0]; ++ i) tmp[1][i] = ls[tmp[1][i]];
        for(register int i = 1; i <= tmp[0][0]; ++ i) tmp[0][i] = ls[tmp[0][i]];
        return Query(l, mid, k - sum);
    }
}
inline int lowbitQuery(int u, int v, int k){
    tmp[0][0] = tmp[1][0] = 0;
    int lca = LCA(u, v);
    if(depth[u] + depth[v] - depth[lca] - depth[fa[lca]] < k) return -INF;
    for(register int i = dfn[u]; i; i -= lowbit(i)) tmp[1][++ tmp[1][0]] = root[i];
    for(register int i = dfn[v]; i; i -= lowbit(i)) tmp[1][++ tmp[1][0]] = root[i];
    for(register int i = dfn[lca]; i; i -= lowbit(i)) tmp[0][++ tmp[0][0]] = root[i];
    for(register int i = dfn[fa[lca]]; i; i -= lowbit(i)) tmp[0][++ tmp[0][0]] = root[i];
    return Query(1, len, k);
}
inline void work(void){
    dfs1(1, 0); dfs2(1, 1);
    for(register int i = 1; i <= n; ++ i) a[i] = lower_bound(arr + 1, arr + len + 1, a[i]) - arr;
    for(register int i = 1; i <= q; ++ i){
        if(query[i].k == 0) query[i].b = lower_bound(arr + 1, arr + len + 1, query[i].b) - arr;
    }
    for(register int i = 1; i <= n; ++ i){
        lowbitModify(dfn[i], a[i], 1); lowbitModify(dfn[i] + siz[i], a[i], -1);
    }
    for(register int i = 1; i <= q; ++ i){
        //错误笔记:把q写成n导致TLE
        if(query[i].k == 0){
            int p = query[i].a;
            lowbitModify(dfn[p], a[p], -1); lowbitModify(dfn[p] + siz[p], a[p], 1);
            a[p] = query[i].b;
            lowbitModify(dfn[p], a[p], 1); lowbitModify(dfn[p] + siz[p], a[p], -1);
        }
        else {
            int ans = lowbitQuery(query[i].a, query[i].b, query[i].k);
            if(ans == -INF) printf("invalid request!\n");
            else printf("%d\n", arr[ans]);
        }
    }
}

int main(){
    init(); work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/FlySakura/p/12236426.html