首页 > 其他分享 >QBXT 4242.小葱拿糖

QBXT 4242.小葱拿糖

时间:2024-09-25 22:28:04浏览次数:8  
标签:fa int max 4242 st QBXT depth include 小葱

统计五个数组,\(v_i\) \(i\)点的美味值(权值),f_i 当前节点到根节点的权值和,\(m_{i,0/1}\) i 的最大/次大向下走的路径权值和(不包括点 \(i\) ),\(g_{i,0/1}\) 从 i 点向上走的,或者走其他子树的最大路径(0/1 = 包含/不包含 \(m_{i,0}\))。\(st_i\) i 在不在 fa 的 \(m_{i,0}\) 上。

其中除了 g 都易得,而 g 可以通过在树上递推,递推出来,递推式子为:
g[u][0] = max(g[fa][st[u]], m[u][0]) + v[u];
g[u][1] = max(g[fa][st[u]], m[u][1]) + v[u];
为了省时间就直接给代码了,fa 是 u 的父节点。可以想想怎么出来的

主要分为 4 种。

  1. p,q 都不是 LCA。这种 pq 之间路径易得,为 \(f_p + f_q - 2f_{lca} + v_{lca}\), 而在 q 点还能往下走任意子树路径,即加上 \(m_{i,0}\)。即:f[i] + f[j] - 2 * f[p] + v[p] + m[j][0]
  2. p 是 LCA,那么 q 在 p 下方,\(m_{i,0}\) 一定可以取到,即f[j] - f[i] + v[i] + m[j][0]
  3. q 是 LCA,此时向上取,即使用 g 数组,为 f[i] - f[j] + g[j][st[k]]
  4. p,q 相等 即向上或者向下走,即 max(m[i][0] + v[i], g[i][0])
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>

using namespace std;

const int N = 100010, M = N * 2;

int n, mk;
int h[N], e[M], ne[M], w[M], idx;
int f[N], g[N][2], m[N][2]; // m不算i本身 g含本身
bool st[N];
int depth[N], fa[N][20];
int v[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void dfs1(int u, int fas)
{
    depth[u] = depth[fas] + 1;
    fa[u][0] = fas;
    for (int i = 1; i <= 17; i ++ )
    {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    f[u] += v[u] + f[fas];
    int last = -1;
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (fas == j) continue;
        dfs1(j, u);
        if (m[j][0] + v[j] > m[u][0] || last == -1)
        {
            m[u][1] = m[u][0];
            m[u][0] = m[j][0] + v[j];
            st[j] = true;
            st[last] = false;
            last = j;
        }
        else if (m[j][0] > m[u][1])
        {
            m[u][1] = m[j][0] + v[j]; 
        }
    }
}

void dfs2(int u, int fa)
{
    g[u][0] = max(g[fa][st[u]], m[u][0]) + v[u];
    g[u][1] = max(g[fa][st[u]], m[u][1]) + v[u];
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (fa == j) continue;
        dfs2(j, u);
    }
}

int lca(int a, int b)
{
    if (depth[a] < depth[b]) swap(a, b);
    
    for (int i = 17; i >= 0; i -- )
        if (depth[fa[a][i]] >= depth[b])
            a = fa[a][i];
            
    if (a == b) return b;
    
    for (int i = 17; i >= 0; i -- )
        if (fa[a][i] != fa[b][i])
        {
            a = fa[a][i];
            b = fa[b][i];
        }
    return fa[a][0];
}

int main()
{
//     freopen("take.in","r",stdin);
// 	freopen("take.out","w",stdout);
    cin >> n >> mk;
    
    for (int i = 1; i <= n; i ++ ) scanf("%d", &v[i]);
    memset(h, -1, sizeof h);
    for (int i = 1; i < n; i ++ )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b);
        add(b, a);
    }
    
    
    dfs1(1, 0);
    dfs2(1, 0);
    
    
    while (mk -- )
    {
        int i, j, sum = 0;
        scanf("%d%d", &i, &j);
        int p = lca(i, j);
        
        if (i == j) sum = max(m[i][0] + v[i], g[i][0]);
        else if (p == i)
        {
            sum = f[j] - f[i] + v[i] + m[j][0];
        }
        else if (p == j)
        {
            int k = i; // 用于判断是否占用了 m0
            for (int i = 17; i >= 0; i -- )
            {
                if (depth[fa[k][i]] > depth[j])
                    k = fa[k][i];
            }
            sum = f[i] - f[j] + g[j][st[k]];
        }
        else 
        {
            sum = f[i] + f[j] - 2 * f[p] + v[p] + m[j][0];
        }
        printf("%d\n", sum);
    }
    
    
    return 0;
}

标签:fa,int,max,4242,st,QBXT,depth,include,小葱
From: https://www.cnblogs.com/blind5883/p/18432374

相关文章

  • 2024QBXT暑假j组精英营Day2
    \(一\)\(数据结构\)\(1\)\(链表\)\(1.0\)\(介绍\)链表分为单向链表和双向链表单向链表即当前链表只指向下一个元素双向链表即对于每个元素,记录其前面一个元素,也记录其后面一个元素。链表不建议使用STL的某些元素进行替代,手写链表更为方便。\(1.1\)\(单向链表\)\(1.......
  • QBXT五一集训DAY4笔记
    \(Day\)\(4\)图论图论主要分为\(4\)个方面1.最短路2.二分图匹配3.生成树4.强连通(这个超纲了,不讲)在介绍完理论知识后,我们会逐一讨论它们图图是由点和边构成的边又分为有向边和无向边,因此图可以分为有向图和无向图无向图的度指的是一个点连了多少条边有向图的入度指的......
  • QBXT五一集训DAY3笔记
    \(Day\)\(3\)位运算位运算包含了五个运算符,分别是:&与只有两个对应位都为\(1\)时才为\(1\)|或只要两个对应位中有一个\(1\)时就为\(1\)^异或只有两个对应位不同时才为\(1\)<<左移如\(n<<i\)表示将\(n\)的二进制向左移动\(i\)位,等价于\(n*2^i\)>......
  • QBXT五一集训DAY1笔记
    \(Day1\)\(ASCII\)简单来说,\(ASCII\)其实就是字符与数字之间的映射比如说,\('a'\)的\(ASCII\)就是\(97\)模运算:%来复习一下小学数学:\(a/b=c……d\)这里的\(d\)就是\(a\)除以\(b\)的余数,在计算机中,用%来表示通过这个式子,我们进而得出\(a=b*c+d\)请一定要记住这......
  • 【QBXT 2023 冬】NOIP 突破营 补题清单
    题单:第一部分第二部分题解有时间就写,一般会咕。P5691[NOI2001]方程的解数简单的折半搜索。直接搜索时间复杂度是\(O(m^6)-O(m^6\logp_i)\)的(快速幂),无法通过。考虑优化,首先我们对上面的式子做一个变形:\[\sum_{i=1}^{n}k_ix_i^{p_i}=0\]即\[\sum_{i=1}^{\lfloor\frac......
  • 济南QBXT - 2024游记
    先吐槽一下,宾馆的网实在太差了,我们甚至都连到别的屋了()Day-11~Day-1好想润去济南玩啊。。。其实只是不想写作业Day0终于坐上车力,但是为什么这次的车这么挤,和上次\(CSP-J\)的车差了一大截,十个人勉强挤开,但加上行李整个车感觉刚好满载的样子(史在车上靠着老佛烨qy,在......
  • qbxt 突破营 Day7 T3
    小葱想要吃糖,小葱将拿出来的N颗糖排成一排,第\(i\)颗糖的美味值为\(a_i\)。小葱很喜欢吃糖,所以小葱会从\(N\)颗糖选择不超过\(K\)段不相交的区间的糖果吃掉。但是小葱同学不希望别人吃到和他美味度差不多的糖,所以对于一颗没被吃掉的糖,小葱希望这颗糖美味度比他吃的糖的美味度最大......
  • qbxt 突破营 Day7 T2
    小葱将买来的糖放进了冰箱冷藏,但是小葱想吃糖了,小葱希望把自己想吃的糖从冰箱里面拿出来。具体来说,小葱同学的冰箱是一棵\(N\)个点的树,每个点有一颗糖,第\(i\)个点的糖的美味值是\(a_i\)。小葱每次取糖会从根节点出发,指定一个目标节点\(p\),走到\(p\)点并且把这条路径上的所有糖取......
  • qbxt 突破营 Day1 T4
    考虑经典的俄罗斯方块游戏,二维平面上有若干个积木,他们会受重力的影响下落并堆叠。注意,积木只会竖直下落,如果下落过程中碰到了别的积木那么就会停下。例如下图:不同颜色的块代表了不同的积木,这些积木下落之后会形如下图:积木的形状可以任意的,可能跟传统的俄罗斯方块有一些不同,比......
  • 再谈 qbxt2023国庆刷题 Day7 T2 树
    T2倍增+换根即可,但赛时难写赛时想得线段树二分,也可from:https://www.cnblogs.com/fox-konata/p/17742669.html回头一看老师代码,发现换根换的非常神奇,长见识了方法0:第一次思考,以为要记录走排名为\(a_x\)和\(a_x+1\)的两个倍增数组,但发现并不好合并,也许可以憋出来,但还是......