CF600E Lomsat gelral(线段树合并)

link

题目大意:给以1为根的一棵树,求树上每个点子树中出现次数最多的权值(如果有多个就求他们的和)

对每个点开一个线段树维护子树内权值的桶,dfs时候线段树合并就行了。

因为最后线段树一共插入最多 \(O(n\log n)\) 个节点,每个节点最多会被合并一次,所以复杂度是 \(O(n\log n)\) 的。

#include <cstdio>
#include <vector>
using namespace std;

struct fuck { int maxval; long long sum; } tree[2333333];
int lc[2333333], rc[2333333], tot;
int n, val[100010], fa[100010], rt[100010];
vector<int> out[100010];
long long ans[100010];

fuck operator*(const fuck &a, const fuck &b)
{
    if (a.maxval > b.maxval) return a;
    if (a.maxval < b.maxval) return b;
    return (fuck){a.maxval, a.sum + b.sum};
}

int mg(int x1, int x2, int cl, int cr)
{
    if (x1 == 0) return x2;
    if (x2 == 0) return x1;
    if (cl == cr)
    {
        tree[x1] = (fuck){tree[x1].maxval + tree[x2].maxval, tree[x1].sum};
        return x1;
    }
    int mid = (cl + cr) / 2;
    lc[x1] = mg(lc[x1], lc[x2], cl, mid);
    rc[x1] = mg(rc[x1], rc[x2], mid + 1, cr);
    tree[x1] = tree[lc[x1]] * tree[rc[x1]];
    return x1;
}

void chenge(int &x, int cl, int cr, int pos, int val)
{
    if (x == 0) x = ++tot;
    if (cl == cr) { tree[x].maxval++; tree[x].sum = cl; return; }
    int mid = (cl + cr) / 2;
    if (pos > mid) chenge(rc[x], mid + 1, cr, pos, val);
    else chenge(lc[x], cl, mid, pos, val);
    tree[x] = tree[lc[x]] * tree[rc[x]];
}

void dfs(int x)
{
    for (int i : out[x]) if (fa[x] != i)
    {
        fa[i] = x; dfs(i), rt[x] = mg(rt[x], rt[i], 1, n);
    }
    chenge(rt[x], 1, n, val[x], 1);
    ans[x] = tree[rt[x]].sum;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
    for (int x, y, i = 1; i < n; i++)
    {
        scanf("%d%d", &x, &y);
        out[x].push_back(y), out[y].push_back(x);
    }
    dfs(1);
    for (int i = 1; i <= n; i++) printf("%I64d ", ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/oier/p/10586807.html

时间: 2024-10-03 21:34:34

CF600E Lomsat gelral(线段树合并)的相关文章

codeforces 600E . Lomsat gelral (线段树合并)

You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the subtree of vertex v more times than colour c. So it'

CF600E Lomsat gelral 【线段树合并】

题目链接 CF600E 题解 容易想到就是线段树合并,维护每个权值区间出现的最大值以及最大值位置之和即可 对于每个节点合并一下两个子节点的信息 要注意叶子节点信息的合并和非叶节点信息的合并是不一样的 由于合并不比逐个插入复杂度高,所以应是\(O(nlogn)\)的 #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #i

CodeForces 600E Lomsat gelral(线段树合并)

题目链接:http://codeforces.com/problemset/problem/600/E You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the

线段树合并:从入门到放弃

感谢这篇博客(这里跳转)以及邱宇大神的讲解,我也算作入门(自闭)了. 需要掌握的前置知识点:动态开点线段树.权值线段树. 一.合并思想 线段树合并,就是指建立一颗新的线段树,保存原有的两颗线段树的信息. 那么就是: 假设现在合并到了线段树的a.b某一个pos 如果a在这个区间有pos,b没有,那么新的线段树pos位置赋值为a 如果b在这个区间有pos,a没有,那么新的线段树pos位置赋值为b 如果a.b都有,那么继续 如果此时处理到了两颗线段树的叶子节点,就把b在pos的值加到a上,把新线段树上

【BZOJ4399】魔法少女LJJ 线段树合并

[BZOJ4399]魔法少女LJJ Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味:小猴在枝头悠来荡去,好不自在:各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果:鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境”SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.

BZOJ 4756 线段树合并(线段树)

思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=100050; int n,col[N],cpy[N],tree[N*100],lso

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例,submit,1A! 哇真的舒服 调试输出懒得删了QwQ #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include

[BZOJ3545] [ONTAK2010]Peaks(线段树合并 + 离散化)

传送门 由于困难值小于等于x这个很恶心,可以离线处理,将边权,和询问时的x排序. 每到一个询问的时候,将边权小于等于x的都合并起来再询问. .. 有重复元素的线段树合并的时间复杂度是nlog^2n #include <cstdio> #include <iostream> #include <algorithm> #define N 500001 int n, m, q, cnt, tot, size; int sum[N * 10], ls[N * 10], rs[N