一句话题意:树上路径带修第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;
}
原文地址:https://www.cnblogs.com/FlySakura/p/12236426.html
时间: 2024-10-11 05:44:27