fhqTreap在启发式合并时候要怎么维护标记啊
  • 板块学术版
  • 楼主STDquantum
  • 当前回复0
  • 已保存回复0
  • 发布时间2020/10/8 19:49
  • 上次更新2023/11/5 11:31:43
查看原帖
fhqTreap在启发式合并时候要怎么维护标记啊
135631
STDquantum楼主2020/10/8 19:49

大致题意就是:dfs 时,在子树里查询权值大于 kk 的子节点的权值和,然后要在子树里每个节点都加上一个 ww(每次加的不一样)。然后把子树合并。

我的想法:在子树里以权值 k1k-1 split 一下,然后把大于等于 kk 的那个根的 sumsum 输出。之后启发式合并每个子树。

遇到的问题是:在输出答案的时候时对时错,输出树的中序遍历发现权值不单调增加。

可能的猜测:维护权值和打标记或者传标记的时候出现了问题,导致合并的时候出锅了。

输入格式:对于 22nn 每个节点读入 faifa_iwiw_iwiw_i 是要加到子树所有节点的那个值。之后是离线了询问,查询的就是题意里的东西。

extra:还想问一下大佬们这种题调试的时候都要输出什么啊。

感谢看我这么多字和毒瘤代码。。

代码:

#include <bits/stdc++.h>
using namespace std;

#define p pair<int, int>
typedef vector<p>::iterator iter;
typedef long long ll;
const int N = 2e5 + 10;

#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
vector<p> v[N], query[N];
int sz[N], pri[N], ch[N][2];
int cnt, root[N];
ll ans[N], val[N], sum[N], tag[N];

void get(int x) { // 中序遍历
    if (!x) return;
    get(ls(x));
    cerr << val[x] << " ";
    get(rs(x));
}
inline void pushup(int x) {
    sz[x] = sz[ls(x)] + sz[rs(x)] + 1;
    sum[x] = sum[ls(x)] + sum[rs(x)] + val[x];
}
inline void add(int x, ll w) { // 加标记
    val[x] += w, sum[x] += w * sz[x], tag[x] += w;
}
inline void pushdown(int x) {
    if (tag[x]) {
        if (ls(x)) add(ls(x), tag[x]);
        if (rs(x)) add(rs(x), tag[x]);
        tag[x] = 0;
    }
}
inline int newNode(int w) {
    sz[++cnt] = 1, val[cnt] = sum[cnt] = w, pri[cnt] = rand();
    return cnt;
}
void split(int now, ll w, int &x, int &y) {
    if (!now) {
        x = y = 0;
    } else {
        pushdown(now);
        if (val[now] <= w) {
            x = now, split(rs(now), w, rs(now), y);
        } else {
            y = now, split(ls(now), w, x, ls(now));
        }
        pushup(now);
    }
}
int merge(int x, int y) {
    if (!x || !y) return x | y;
    if (pri[x] < pri[y]) {
        pushdown(x);
        rs(x) = merge(rs(x), y);
        return pushup(x), x;
    } else {
        pushdown(y);
        ls(y) = merge(x, ls(y));
        return pushup(y), y;
    }
}
int cass;
void insert(int &root, int x) {
    int a, b;
    ll v = val[x];
    split(root, v, a, b);
    root = merge(merge(a, x), b);
}
void transform(int x, int &y) { // 递归进行启发式合并
    if (!x) return;
    transform(ls(x), y), transform(rs(x), y);
    ls(x) = rs(x) = 0;
    insert(y, x);
}
int treeMerge(int x, int y) {
    if (sz[x] > sz[y]) swap(x, y);
    return transform(x, y), y;
}
ll queryAns(int &x, ll w) { // 查询答案
    int a, b;
    ll ans;
    split(x, w - 1, a, b);
    ans = sum[b];
    x = merge(a, b);
    return ans;
}

void dfs(int x) {
    root[x] = newNode(0);
    for (iter it = v[x].begin(); it != v[x].end(); ++it) {
    	// it->first是到的节点
        // it->second是要给子树加上的权值
        dfs(it->first);
        add(root[it->first], it->second);
        root[x] = treeMerge(root[x], root[it->first]);
    }
    for (iter it = query[x].begin(); it != query[x].end(); ++it) {
    	// it->first是要查询的值k
        // it->second是查询的编号(离线用)
        ans[it->second] = queryAns(root[x], it->first);
    }
}

int n, q;
int main() {
    srand(20040410), read(n);
    for (int i = 2, x, y; i <= n; ++i)
        read(x), read(y), v[x].push_back(p(i, y));
    read(q);
    for (int i = 1, u, k; i <= q; ++i) {
        read(u), read(k);
        query[u].push_back(p(k, i));
    }
    dfs(1);
    for (int i = 1; i <= q; ++i) { write(ans[i]), putchar('\n'); }
}
2020/10/8 19:49
加载中...