首页 > 其他分享 >AC466A 2024省选联测19 寄(post)

AC466A 2024省选联测19 寄(post)

时间:2024-02-16 21:34:23浏览次数:20  
标签:cnt Esl 19 省选 2024 int array include dis

题意

一棵有边权的树,给定 \(m\) 个关键点,让你选择若干个点,使得每个关键点到你选择的点的距离的最小值之和加上选择的点的个数乘 \(C\) 最小。

求这个最小值。

\(n \le 3000\)

Sol

考虑将选择点的个数扔掉,直接考虑对于每个点加上 \(C\) 的贡献。

设 \(f_{i, j}\) 表示 \(i\) 的贡献点为 \(j\),\(i\) 子树内所有点的贡献。

考虑转移,注意到一个贡献点所贡献到的关键点一定形成一个连通块,所以只需要考虑当前点与儿子的关键点相同即可。

设 \(f_{i, 0}\) 表示 \(min_{j = 1} ^ {n} f_{i, j}\)。

可得:

\[f_{u, i} = \min(f_{v, i} - C, f_{v, 0}) \]

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <cmath>
#include <tuple>
#define int long long
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')
            flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
const int N = 3e3 + 5, M = 6e3 + 5, inf = 2e18;

namespace G {

array<int, N> fir;
array<int, M> nex, to, len;

int cnt = 1;

void add(int x, int y, int z) {
    cnt++;
    nex[cnt] = fir[x];
    to[cnt] = y;
    len[cnt] = z;
    fir[x] = cnt;
}

}  // namespace G

namespace Esl {

array<int, M> idx, dfn;
array<int, N> fa, dep, dis;
int cnt;

void dfs(int x) {
    cnt++;
    dfn[x] = cnt;
    idx[cnt] = x;
    for (int i = G::fir[x]; i; i = G::nex[i]) {
        if (G::to[i] == fa[x])
            continue;
        fa[G::to[i]] = x;
        dep[G::to[i]] = dep[x] + 1;
        dis[G::to[i]] = dis[x] + G::len[i];
        dfs(G::to[i]), cnt++, idx[cnt] = x;
    }
}

array<array<int, 22>, M> sT;
array<int, M> lg;

void init() {
    for (int i = 1; i <= cnt; i++) lg[i] = log2(i);
    for (int i = 1; i <= cnt; i++) sT[i].fill(inf);
    for (int i = 1; i <= cnt; i++) sT[i][0] = dfn[idx[i]];
    for (int j = 1; j < 21; j++)
        for (int i = 1; i + (1 << j) - 1 <= cnt; i++)
            sT[i][j] = min(sT[i][j - 1], sT[i + (1 << (j - 1))][j - 1]);
}

int query(int l, int r) {
    tie(l, r) = minmax(dfn[l], dfn[r]);
    int len = lg[r - l + 1];
    return idx[min(sT[l][len], sT[r - (1 << len) + 1][len])];
}

}  // namespace Esl

array<array<int, N>, N> f;
array<int, N> val;

int dist(int x, int y) { return Esl::dis[x] + Esl::dis[y] - 2 * Esl::dis[Esl::query(x, y)]; }

void dfs(int x, int n, int C) {
    for (int i = 1; i <= n; i++) {
        f[x][i] = C + val[x] * dist(x, i);
        /* write(x), putchar(32); */
        /* write(i), putchar(32); */
        /* write(dist(x, i)), puts("@"); */
    }
    for (int i = G::fir[x]; i; i = G::nex[i]) {
        if (G::to[i] == Esl::fa[x])
            continue;
        dfs(G::to[i], n, C);
        for (int j = 1; j <= n; j++) f[x][j] += min(f[G::to[i]][j] - C, f[G::to[i]][0]);
    }
    f[x][0] = inf;
    for (int i = 1; i <= n; i++) f[x][0] = min(f[x][i], f[x][0]);
}

signed main() {
    freopen("post.in", "r", stdin);
    freopen("post.out", "w", stdout);
    int n = read(), m = read(), C = read();
    for (int i = 2; i <= n; i++) {
        int x = read(), y = read(), z = read();
        G::add(x, y, z), G::add(y, x, z);
    }
    for (int x; m--;) x = read(), val[x]++;
    Esl::dfs(1), Esl::init();
    dfs(1, n, C);
    write(f[1][0]), puts("");
    return 0;
}

标签:cnt,Esl,19,省选,2024,int,array,include,dis
From: https://www.cnblogs.com/cxqghzj/p/18017497

相关文章

  • 2024.2.16 そんな凡庸を探して、探している
    Namid[A]me好听呢。可惜了。今天DP专题感觉laofu选的题有点经典,导致我有一半时间在摸鱼,不过还是写了点题的。怎么西工大附中有糖醋茄子这种神秘菜啊。ICPC2020MacauBBoringProblem其实不一定懂完了,试着说一说。显然询问没什么用,问题本质是要求解一个AC自动机上游......
  • CF1928
    第一次写整场CF的题解。A:只有一边长度是$2$的倍数才可以选择剪下拼成另一个长方形,两边都判一下就行了:记录B:容易发现,加上某个排列长度为$n$的后,最多可以使两个相减为$n-1$的两个元素相等,于是双指针即可。记录C:先枚举他所得到的数是若干轮$2k-2$中的前$k$个还是......
  • P10149 [Ynoi1999] XM66F题解
    题解首先,问题是静态的区间查询问题,一眼莫队。那么我们就需要考虑所需要维护的内容在区间扩增或者缩减时的变化如何快速维护。我们可以先写出对于区间\([l,r]\)来说,满足\(l\lei<j<k\ler\)的有序三元组\((i,j,k)\)数量的表达式,方便拆式子:\[\sum\limits_{i=l}^{r}......
  • 8.【2024初三年前集训测试3】
    \(\Huge打了一场模拟赛,终于不垫底了。qwq\)2024初三年前集训测试3T1夕景昨日\(90pts\)不好想,一直做到最后了,然后发现过不了样例,发现读假题了\(\Largeqwq\Huge......
  • 2024.2.16模拟赛总结
    前言:这次不太好,rank6,挂了108.5分,不挂就随便rank1了T1直接状压,设\(f[S][i][j][0/1]\)表示当前选的集合为S,最后两个分别为i,j的方案数和最优解,然后直接跑有亿点细节1:要开longlong,方案数可能很大(造一个完全图)2,要从合法的状态转移3,特判只有一个点的数据T2一道计算几何题首先......
  • PKUWC&WC2024游记
    Day-?A_zjzj踢球韧带被铲断了。本来好像是还没断的,但他被铲之后觉得没事又去打乒乓球了(Day-1请了个假回家睡大觉。早上模拟赛写了2hT4发现假了,最后20min火速改了个正确的出来,提前10minAK了。看不懂呼啸山庄/kkDay0睡大觉!早上九点到机房,发现机房里只有狗哥,我......
  • CF1929
    CF1929总结Url:https://codeforces.com/contest/1929Rating:https://codeforces.com/bestRatingChanges/12561378C误解了题意,以为赌场会配合他前面x次都输然后赢最后一场。原来赌场不会配合Sasha。他要分配最好策略,不论赌场怎么搞都能赚钱。然后注意取整,本来想hack一个人,没h......
  • P1198 [JSOI2008] 最大数
    原题链接题解1:单调栈+并查集?单调栈特性:栈内元素大小和序号由栈底到栈顶具有单调性,本题大小单调减,序号单调增维护:新元素入栈时,栈内剩余的所有小于该元素的元素出栈,并视新元素为集合首领,然后新元素入栈查询:查询集合首领即可code1#definelllonglong#include<bits/stdc++.h>......
  • 20240215
    为了便于开发和维护,一般来说应用应当有界面层和数据层,界面层用于在屏幕上显示应用数据,数据层包含应用的业务逻辑并公开应用数据。界面层也由两部分,一部分呈现界面和数据,一部分处理数据和逻辑。简单的用我已知的知识理解,就是看得见的HTMLCSS与看不见的JavaScript,虽然也常常用Java......
  • CF1931G. One-Dimensional Puzzle
    CF1931G思路观察可得,要拼出合法序列只有12交替同时34插入12和21之间;当1和2的相差超过1时,多出来拼图的无法拼接成合法序列,所以答案是0;当1和2都为0时,只有3或者只有4的情况答案是1,其他情况答案是0;当1比2多一个时:只能是前后都是1,比如12121,观察得,3只能插在1的后面,4只能插在1......