CF1303G Sum of Prefix Sums

原题链接

这题好毒瘤啊!

首先看到是树上查询全局某式子的最大值,珂以想到这题无外乎是链分治(\(\text{dsu on tree}\))或点分治。作为一个专业的链分治选手, 窝在比赛中想了\(30\)min也不会。比赛后想了想,好像\(\text{dsu on tree}\)不星(珂能还是窝太菜了)。

点分治。因为是全局最大值,所以珂以不用在分治里容斥。

假设当前的子树的根是\(\text{u}\)。

由于不用容斥,所以要确保在分治里面路径不能有重复边,这个珂以枚举\(\text{u}\)的儿子\(\text{v}\),然后枚举\(\text v\)为根的子树中的节点\(\text y\),另外开一个玩意儿维护之前的所有节点\(\text x\)的信息,其中\(\text x\)不在子树\(\text v\)里面。这样就珂以避免路径重复了。

因为询问是有方向的,为了方便,每一次枚举\(\{\text x,\text y\}\)时,默认方向为\(\text x\rightarrow\text u\rightarrow \text y\)。这样在枚举完\(\text u\)的儿子\(\text v\)之后,还要在反过来枚举一遍,即枚举另一个方向。

窝们考虑维护\(\text x\)的什么信息。设\(\text x\rightarrow \text y\)的答案为\(\operatorname{ans}(\text x,\text y)\),\(\text x\rightarrow\text y\)路径的长度为\(\operatorname{len}(\text x,\text y)\)

\(\operatorname{ans}(\text x,\text y)=\operatorname{ans}(\text v,\text y)+\operatorname{ans}(\text x,\text u)+\operatorname{len}(\text v,\text y)\sum\limits_{w\in \text x\rightarrow\text u}a_w\)

这里,\(\operatorname{ans}(\text v,\text y),\operatorname{len}(\text v,\text y)\)是定值。

所以这个式子就是一个\(a+x+by\)的结构,其中\(a,b\)是珂能会变的定值。

也就是说,窝们要搞一个数据结构,支持:

  1. 插入二元组\((x,y)\)
  2. 给定\(c\),查询\(\max\{x+cy\}\)

到这儿,想必神仙们都会用李超线段树来切掉这题了吧

然后由于窝这个菜鸡不会李超线段树,只能用其他方法。

和李超线段树做法一样,窝们把\((y,x)\)转化为平面上一条直线的\((k,b)\),然后查询就是询问\(\max\{f(c)\}\)。

窝采用动态凸包,用平衡树维护哪些直线珂能成为最大值,按照\(k\)排序。

插入直线时,用叉积判断一条直线是否珂能成为最大值。

查询时,就直接平衡树上二分每一条直线\(l\)是否满足最大值的要求,即\(c\)是否在\(l\cap \operatorname{nxt}(l)\)左边。

放一下代码:

// Code by H~$~C
#include <bits/stdc++.h>
using namespace std;

#ifndef LOCAL_JUDGE
static char _in_buf[100000], *_in_p1 = _in_buf, *_in_p2 = _in_buf;
#define gc (__builtin_expect(_in_p1 == _in_p2, 0) && (_in_p2 = (_in_p1 = _in_buf) +         fread(_in_buf, 1, 100000, stdin), _in_p1 == _in_p2) ? -1 : *_in_p1++)
#else
#define gc getchar()
#endif
inline int read() {
  register char ch = gc;
  register int x = 0;
  while (ch < 48 || ch > 57) ch = gc;
  while (ch > 47 && ch < 58) x = (x << 3) + (x << 1) + (ch ^ 48), ch = gc;
  return x;
}

static const int Maxn = 150005;

int n;
long long a[Maxn];
long long ans;
vector<int> g[Maxn];

// use to solve something that Li-Chao-Tree do
// add a line f(x), query max{f(a)}
namespace HULL {
  bool flag;
  struct line {
    long long k, b;
    mutable function<const line* ()> nxt;
    friend bool operator < (const line &a, const line &b) {
      if (!flag) return a.k < b.k;
      const line *s = a.nxt();
      if (!s) return false;
      return a.b - s->b < b.b * (s->k - a.k);
    }
  };
  struct dynamic_hull
  : public multiset<line> {
    // check if the line is maximum somewhere
    inline bool bad(iterator it) {
      if (it == this->end()) return false;
      auto nxt = next(it);
      if (it == this->begin()) {
        if (nxt == this->end()) return false;
        return it->k == nxt->k && it->b <= nxt->b;
      }
      auto prv = prev(it);
      if (nxt == this->end()) {
        return it->k == prv->k && it->b <= prv->b;
      }
      return (prv->b - it->b) * (nxt->k - it->k) >= (it->b - nxt->b) * (it->k - prv->k);
    }
    // add a new line to the current hull
    inline void add(long long k, long long b) {
      auto it = this->insert((line){k, b});
      it->nxt = [=]() { return next(it) == this->end() ? nullptr : &*next(it); };
      if (bad(it)) return void(this->erase(it));
      while (next(it) != this->end() && bad(next(it))) this->erase(next(it));
      while (it != this->begin() && bad(prev(it))) this->erase(prev(it));
    }
    // query the maximum value where <x> = x
    long long query(long long x) {
      if (this->empty()) return -1LL << 60;
      flag = true;
      line l = *lower_bound((line){0, x});
      flag = false;
      return l.k * x + l.b;
    }
  };
}
using HULL::dynamic_hull;

bool vis[Maxn];
int sz[Maxn], mxson[Maxn];
int root, total, mnson;

void get_root(int u, int fa) {
  sz[u] = 1, mxson[u] = 0;
  for (int v: g[u]) {
    if (v == fa || vis[v]) continue;
    get_root(v, u), sz[u] += sz[v];
    mxson[u] = max(mxson[u], sz[v]);
  }
  mxson[u] = max(mxson[u], total - sz[u]);
  if (mnson > mxson[u]) {
    root = u;
    mnson = mxson[u];
  }
}

int dep[Maxn];
long long dis[Maxn], d[Maxn];
dynamic_hull h;

void dfs_query(int u, int fa, int dep, long long dis, long long sum) {
  dis += a[u];
  sum += dis;
  ans = max(ans, h.query(dep) + sum);
  for (int &v: g[u]) {
    if (v == fa || vis[v]) continue;
    dfs_query(v, u, dep + 1, dis, sum);
  }
}
void dfs_modify(int u, int fa, int dep, long long dis, long long sum) {
  dis += a[u];
  sum += a[u] * dep;
  h.add(dis, sum);
  for (int &v: g[u]) {
    if (v == fa || vis[v]) continue;
    dfs_modify(v, u, dep + 1, dis, sum);
  }
}

void solve(int u) {
  ans = max(ans, a[u]);

  h.clear();
  for (int v: g[u]) {
    if (vis[v]) continue;
    dfs_query(v, 0, 1, 0LL, 0LL);
    dfs_modify(v, 0, 2, a[u], a[u]);
  }
}

void divide_root(int u) {
  vis[u] = true;

  solve(u);
  reverse(g[u].begin(), g[u].end());
  solve(u);

  for (int v: g[u]) {
    if (vis[v]) continue;

    total = sz[v], root = 0;
    mnson = 0x3f3f3f3f;
    get_root(v, 0);

    divide_root(root);
  }
}

int main() {
  n = read();
  for (int i = 1; i < n; ++i) {
    int u = read(), v = read();
    g[u].push_back(v);
    g[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i) {
    a[i] = read();
  }

  total = n, root = 0;
  mnson = 0x3f3f3f3f;
  get_root(1, 0);

  divide_root(root);

  printf("%lld\n", ans);
  return 0;
}

原文地址:https://www.cnblogs.com/libra9z/p/12387308.html

时间: 2024-10-01 19:09:00

CF1303G Sum of Prefix Sums的相关文章

CodeForces 837F - Prefix Sums | Educational Codeforces Round 26

按tutorial打的我血崩,死活挂第四组- - 思路来自FXXL /* CodeForces 837F - Prefix Sums [ 二分,组合数 ] | Educational Codeforces Round 26 题意: 设定数组 y = f(x) 使得 y[i] = sum(x[j]) (0 <= j < i) 求初始数组 A0 经过多少次 f(x) 后 会有一个元素 大于 k 分析: 考虑 A0 = {1, 0, 0, 0} A1 = {1, 1, 1, 1} -> {C(

codeforces:Prefix Sums

题目大意: 给出一个函数P,P接受一个数组A作为参数,并返回一个新的数组B,且B.length = A.length + 1,B[i] = SUM(A[0], ..., A[i]).有一个无穷数组序列A[0], A[1], ... 满足A[i]=P(A[i-1]),其中i为任意自然数.对于输入k和A[0],求一个最小的下标t,使得A[t]中包含不小于k的数值. 其中A[0].length <= 2e5, k <= 1e18,且A[0]中至少有两个正整数. 数学向的题目.本来以为是个找规律的题目

[CF1204E]Natasha,Sasha and the Prefix Sums 题解

前言 本文中的排列指由n个1, m个-1构成的序列中的一种. 题目这么长不吐槽了,但是这确实是一道好题. 题解 DP题话不多说,直接状态/变量/转移. 状态 我们定义f表示"最大prefix sum"之和 变量 f[i][j]为有i个1,j个-1的"最大prefix sum"之和 转移 我们记C[i][j]为\(\left(\begin{matrix} i \\ j\end{matrix}\right)\),那么: \[f[i][j] = \left\{\begin

GenomicRangeQuery /codility/ preFix sums

首先上题目: A DNA sequence can be represented as a string consisting of the letters A, C, G and T, which correspond to the types of successive nucleotides in the sequence. Each nucleotide has an impact factor, which is an integer. Nucleotides of types A,

E. Natasha, Sasha and the Prefix Sums

给定n个 1 m个 -1的全排 求所有排列的$f(a)=max(0,max_{1≤i≤l}∑_{j=1}^{i}a_{j})$之和 组合数,枚举 #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll MOD = 998244853; int n, m; ll C[4002][4002]; ll sum; ll realSum; ll ans; void init() { for(int i=0;

CodeForces - 1204E Natasha, Sasha and the Prefix Sums (组合数学,卡特兰数扩展)

题意:求n个1,m个-1组成的所有序列中,最大前缀之和. 首先引出这样一个问题:使用n个左括号和m个右括号,组成的合法的括号匹配(每个右括号都有对应的左括号和它匹配)的数目是多少? 1.当n=m时,显然答案为卡特兰数$C_{2n}^{n}-C_{2n}^{n+1}$ 2.当n<m时,无论如何都不合法,答案为0 3.当n>m时,答案为$C_{n+m}^{n}-C_{n+m}^{n+1}$,这是一个推论,证明过程有点抽象,方法是把不合法的方案数等价于从(-2,0)移动到(n+m,n-m)的方案数,

CF1024E Natasha, Sasha and the Prefix Sums——DP/数学(组合数)

题面 CF1024E 解析 题意就是要求所有由$n$个$1$.$m$个$-1$构成的序列的最大前缀和的和 算法一$(DP)$ $n$, $m$都小于等于$2000$, 显然可以$DP$ 设$dp[i][j]$表示由$i$个$1$, $j$个$-1$构成的序列的最大前缀和的和 $i$个$1$, $j$个$-1$构成的序列, 可以看做是在$i-1$个$1$, $j$个$-1$的序列的最前面加一个$1$得到,也可以看做是在$i$个$1$, $j-1$个$-1$的序列最前面加一个$-1$得到 这也就意味

CF1204E Natasha, Sasha and the Prefix Sums

题意 给\(n\)个1和\(m\)个0,定义一个01串的权值为它所有前缀和的最大值(包括0),求可以组成的所有不同串的权值和,答案对998244853取模 思路 由于数据较小,本题有个\(O(n^2)\)比较复杂的DP做法,自行百度... 实际上本题用数学规律可以\(O(n)\)做 设\(f_i\)表示权值为\(i\)的01串数量,直接求不容易,再设\(g_i\)为权值至少为\(i\)的01串数量,那么\(f_i=g_i-g_{i+1}\) 利用求卡特兰数列的一种方法:将01串看做从坐标系\((

[LeetCode 1171] Remove Zero Sum Consecutive Nodes from Linked List

Given the head of a linked list, we repeatedly delete consecutive sequences of nodes that sum to 0 until there are no such sequences. After doing so, return the head of the final linked list.  You may return any such answer. (Note that in the example