P4556 [Vani有约会]雨天的尾巴 线段树合并做法*

news/2024/7/15 17:21:03 标签: 图论, 算法

Link
线段树合并的板子题,等刷过几道再去补树剖做法。
注意: 线段树空间开很多倍的同时,不要忘记把root数组也同样开到很多倍

思路

其实就是树上差分+LCA,但空间复杂度 O ( N M ) O(NM) O(NM),通过线段树合并将空间复杂度降至 O ( ( N + M ) log ⁡ ( N + M ) ) O((N+M)\log(N+M)) O((N+M)log(N+M))
具体来说,对树上每个点建立一棵动态开点的权值线段树,支持修改某个位置,维护区间最大值和最大值所在的位置。

代码

const int maxn = 4e5 + 10;
const int maxm = 4e5 + 10;
struct SegmentTree {
    int lc, rc;
    int dat;
#define lc(p) tree[p].lc
#define rc(p) tree[p].rc
#define dat(p) tree[p].dat
} tree[maxn << 5];
int rt[maxn << 5];
int tot;
int x[maxn], y[maxn], z[maxn];
void push(int p) {
    if(lc(p) == 0) {
        dat(p) = dat(rc(p));
        rt[p] = rt[rc(p)];
        return;
    }
    if(rc(p) == 0) {
        dat(p) = dat(lc(p));
        rt[p] = rt[lc(p)];
        return;
    }
    if(dat(lc(p)) >= dat(rc(p))) {
        dat(p) = dat(lc(p));
        rt[p] = rt[lc(p)];
    }
    else {
        dat(p) = dat(rc(p));
        rt[p] = rt[rc(p)];
    }
}
int insert(int p, int l, int r, int pos, int d) {
    if(!p) p = ++tot;
    if(l == r) {
        dat(p) += d;
        rt[p] = pos;
        return p;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid)
        lc(p) = insert(lc(p), l, mid, pos, d);
    else
        rc(p) = insert(rc(p), mid + 1, r, pos, d);
    push(p);
    return p;
}
int merge(int p, int q, int l, int r) {
    if(!p) return q;
    if(!q) return p;
    if(l == r) {
        dat(p) += dat(q);
        return p;
    }
    int mid = (l + r) >> 1;
    lc(p) = merge(lc(p), lc(q), l, mid);
    rc(p) = merge(rc(p), rc(q), mid + 1, r);
    push(p);
    return p;
}
int n;
int Log2[maxn], fa[maxn][30], dep[maxn];
bool vis[maxn];
int head[maxn];
int p;
struct Edge {
    int to, dis = 1, next;
}edge[maxm];
void dfs(int cur = 1, int fath = 0) {
    if(vis[cur]) return;
    vis[cur] = true;
    dep[cur] = dep[fath] + 1;
    fa[cur][0] = fath;
    for(int i = 1; i <= Log2[dep[cur]]; i++)
        fa[cur][i] = fa[fa[cur][i-1]][i-1];
    for(int i = head[cur]; i; i = edge[i].next)
        dfs(edge[i].to, cur);
}
int LCA(int a, int b) {
    if(dep[a] > dep[b])
        swap(a, b);
    while(dep[a] != dep[b])
        b = fa[b][Log2[dep[b]-dep[a]]];
    if(a == b)
        return a;
    for(int k = Log2[dep[a]]; k >= 0; k--)  //跳跃长度从长到短
        if(fa[a][k] != fa[b][k]) {
            a = fa[a][k];
            b = fa[b][k];
        }
    return fa[a][0];
}
void init() {
    for(int i = 1; i <= n; i++) {
        dep[i] = 0;
        head[i] = 0;
    }
    p = 0;
    for(int i = 2; i <= n; i++)
        Log2[i] = Log2[i / 2] + 1;
}
void add_edge(int u, int v, int w = 1) {
    p++;
    edge[p].to = v;
    edge[p].dis = w;
    edge[p].next = head[u];
    head[u] = p;
}
int r = 0;
int ans[maxn];
void calc(int u, int fa) {
    for(int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].to;
        if(v == fa) continue;
        calc(v, u);
        rt[u] = merge(rt[u], rt[v], 1, r);
    }
    ans[u] = rt[rt[u]];
    if(dat(rt[u]) == 0) ans[u] = 0;
}
void solve() {
    tot = 0;
    int m;
    cin >> n >> m;
    init();
    for(int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        add_edge(u, v);
        add_edge(v, u);
    }
    dfs();
    for(int i = 1; i <= m; i++) {
        cin >> x[i] >> y[i] >> z[i];
        r = max(r, z[i]);
    }
    for(int i = 1; i <= m; i++) {
        int lca = LCA(x[i], y[i]);
        rt[x[i]] = insert(rt[x[i]], 1, r, z[i], 1);
        rt[y[i]] = insert(rt[y[i]], 1, r, z[i], 1);
        rt[lca] = insert(rt[lca], 1, r, z[i], -1);
        if(fa[lca][0])
            rt[fa[lca][0]] = insert(rt[fa[lca][0]], 1, r, z[i], -1);
    }
    calc(1, 0);
    for(int i = 1; i <= n; i++)
        cout << ans[i] << endl;
}

http://www.niftyadmin.cn/n/1764892.html

相关文章

atitit.企业管理----商业间谍策略的使用与防务

atitit.企业管理----商业间谍策略的使用与防务 1. 间谍的历史 2 1.1. 公元前10世纪&#xff0c;《旧约全书》中的《士师记》里讲述了参孙的故事是最早的间谍故事。 2 1.2. 蒙古人是第一个把间谍提升到组织利益高度的民族。 3 1.3. 情报立国 3 1.4. 间谍的作用 3 2. 商业间谍的分…

P1600 [NOIP2016 提高组] 天天爱跑步 树上差分*

Link 参考文章 一道我觉得非常好的题目&#xff0c;有些地方还没想清楚&#xff0c;需要再回顾一下。 问题的第一个关键就在于把原问题转化&#xff1a; 有 mmm 个玩家&#xff0c;其中第 iii 个玩家给 SiS_iSi​ 到 lca(Si,TiS_i, T_iSi​,Ti​)的路径上每个点增加一个类型为 …

[转] Matlab中给信号加高斯白噪声的方法

MATLAB中产生高斯白噪声非常方便&#xff0c;可以直接应用两个函数&#xff0c;一个是WGN&#xff0c;另一个是AWGN。WGN用于产生高斯白噪声&#xff0c;AWGN则用于在某一信号中加入高斯白噪声。 1. WGN&#xff1a;产生高斯白噪声 y wgn(m,n,p) 产生一个m行n列的高斯白噪声的…

P4151 [WC2011]最大XOR和路径线性基

link 注意insert的是 res ^ val[v] ^ w vector <ull> B; void insert(ull x) {for(auto b : B)x min(x, x ^ b);for(auto &b : B)b min(b, x ^ b);if(x)B.push_back(x); } int head[maxn], cnt; struct Edge {int to, next;ull w; }edge[maxm]; void add_edge(int…

720012指令

在不开心做的要价1000元的希捷专修软件中,所有F3T(即7200.11 7200.12 5400.6等指令模式下为F3T的)指令. 用CommMonitor软件跟踪出来的,每个都测试可用. 还原设置&#xff1a;F&#xff0c;&#xff0c;22 代修复通病&#xff1a;m0,2,2,0,0,0,0,22 重建译码表&#xff1a;m0,6,…

P4035 [JSOI2008]球形空间产生器 ——高斯消元

Link 一道高斯消元的题目&#xff0c;其实重点还是在如何得出方程组也就是增广矩阵。 代码 const double EPS1e-7; inline int gauss(double a[][N], bool l[], double ans[], const int& n) {int res 0, r 0;for(int i 0; i < n; i)l[i] false;for(int i 0; i …

Bootstrap使用后笔记

Bootstrap Modal 垂直居中 在 bootstrap.js中修改如下代码&#xff1a; Modal.prototype.adjustDialog function () { var modalIsOverflowing this.$element[0].scrollHeight > document.documentElement.clientHeight this.$element.css({ paddingLeft: !this.bodyIsOve…

208. 开关问题 —— 高斯消元

Link 高斯消元问题 其实就是对于每盏灯 xix_ixi​&#xff0c;均有一个数组aaa 如 aaa {0, 1, 1, 0}表示对第 iii 盏灯操作&#xff0c;则第2&#xff0c;3盏灯也会变化&#xff0c;于是构成一个二维矩阵a[i][j]a[i][j]a[i][j]&#xff0c;a[i][j]1a[i][j] 1a[i][j]1则表示操…