点分治+李超树

因为题目要求的是树上所有路径,所以用点分治维护

因为在点分治的过程中相当于将树上经过当前$root$的一条路径分成了两段

那么先考虑如何计算两个数组合并后的答案

记数组$a$,$b$,求得是将$b$数组接到$a$数组的答案

其$a$,$b$的sum of prefix sums分别为$sa$,$sb$,其中$a$数组所有元素的和为$sum$,$b$数组长度为$l$

然后整合一下原来计算的式

其实对于一个数组$P$的sum of prefix sums就是

$n*p_{1}+(n-1)*p_{2}+(n-2)*p_{3}+...+2*p_{n-1}+1*p_{n}$

照着这个式子推出来,将$b$数组接到$a$数组的答案是

$sa+sb+sum*l$

然后这里可以将$sa$看做截距,$sum$看做斜率,$l$为$x$坐标,最终答案为$y$坐标

求的就是每一个$sa$为截距,$sum$为斜率的线段在某一点的最大取值

那么用李超树维护即可

要注意对于树上两个节点$u$,$v$

$u$到$v$的答案和$v$到$u$的答案是不一样的

所以要在合并子树的时候要正着扫一遍,反着扫一遍

还有如果是只有一颗子树需要特判

  1 #pragma GCC optimize(2)
2 #include <bits/stdc++.h>
3 #define int long long
4 using namespace std;
5 const int N=150100;
6 int n,a[N];
7 int sz[N],vi[N],dfn,MAX,root;
8 vector <int> e[N];
9 struct line
10 {
11 int k,b;
12 };
13 struct node
14 {
15 line tag;
16 int ti;
17 }sh[N*4];
18 int cal(int x,line a)
19 {
20 return a.k*x+a.b;
21 }
22 void change(int x,int l,int r,line k)
23 {
24 if (sh[x].ti!=dfn)
25 {
26 sh[x].tag=k;
27 sh[x].ti=dfn;
28 return;
29 }
30 if (cal(l,k)>=cal(l,sh[x].tag) && cal(r,k)>=cal(r,sh[x].tag))
31 {
32 sh[x].tag=k;
33 return;
34 }
35 if (cal(l,k)<=cal(l,sh[x].tag) && cal(r,k)<=cal(r,sh[x].tag))
36 return;
37 int mid=(l+r)>>1;
38 if (cal(mid,k)>cal(mid,sh[x].tag)) swap(k,sh[x].tag);
39 if (cal(l,k)>cal(l,sh[x].tag)) change(x+x,l,mid,k);
40 else change(x+x+1,mid+1,r,k);
41 }
42 int query(int x,int l,int r,int wh)
43 {
44 int ans=(sh[x].ti==dfn)?cal(wh,sh[x].tag):0;
45 if (l==r) return ans;
46 int mid=(l+r)>>1;
47 if (wh<=mid) ans=max(ans,query(x+x,l,mid,wh));
48 else ans=max(ans,query(x+x+1,mid+1,r,wh));
49 return ans;
50 }
51 //李超树
52 void dfs_insert(int x,int fa,int de,line now)
53 {
54 now.k+=a[x];
55 now.b+=de*a[x];
56 change(1,1,n,now);
57 for (register int i=0;i<(int)e[x].size();i++)
58 {
59 int u=e[x][i];
60 if (vi[u] || u==fa) continue;
61 dfs_insert(u,x,de+1,now);
62 }
63 }
64 void dfs_query(int x,int fa,int de,int sb,int s)
65 {
66 sb+=a[x]+s;
67 s+=a[x];
68 MAX=max(MAX,query(1,1,n,de)+sb);
69 for (register int i=0;i<(int)e[x].size();i++)
70 {
71 int u=e[x][i];
72 if (vi[u] || u==fa) continue;
73 dfs_query(u,x,de+1,sb,s);
74 }
75 }
76 void dfs_size(int x,int fa)
77 {
78 sz[x]=1;
79 for (register int i=0;i<(int)e[x].size();i++)
80 {
81 int u=e[x][i];
82 if (vi[u] || u==fa) continue;
83 dfs_size(u,x);
84 sz[x]+=sz[u];
85 }
86 }
87 void dfs_root(int x,int fa,int tot)
88 {
89 bool bl=1;
90 for (register int i=0;i<(int)e[x].size();i++)
91 {
92 int u=e[x][i];
93 if (vi[u] || u==fa) continue;
94 dfs_root(u,x,tot);
95 if (sz[u]>tot/2) bl=0;
96 }
97 if (tot-sz[x]>tot/2) bl=0;
98 if (bl) root=x;
99 }
100 void dfs(int x,int fa,int de,int sa,int sb,int s)
101 {
102 sa+=de*a[x];
103 sb+=s+a[x];
104 s+=a[x];
105 MAX=max(MAX,sb);
106 MAX=max(MAX,sa);
107 for (register int i=0;i<(int)e[x].size();i++)
108 {
109 int u=e[x][i];
110 if (vi[u] || u==fa) continue;
111 dfs(u,x,de+1,sa,sb,s);
112 }
113 }
114 void divide(int x)//点分治
115 {
116 dfn++;
117 vi[x]=1;
118 int cnt=0;
119 for (register int i=0;i<(int)e[x].size();i++)
120 {
121 int u=e[x][i];
122 if (vi[u]) continue;
123 cnt++;
124 line tmp;
125 tmp.k=tmp.b=0;
126 if (cnt!=1) dfs_query(u,x,2,a[x],a[x]);
127 dfs_insert(u,x,1,tmp);
128 }
129 bool bl=(cnt==1);
130 dfn++;cnt=0;
131 for (register int i=(int)e[x].size()-1;i>=0;i--)//反着扫描
132 {
133 int u=e[x][i];
134 if (vi[u]) continue;
135 if (bl) dfs(u,x,2,a[x],a[x],a[x]);//只有一颗子树时的特判
136 cnt++;
137 line tmp;
138 tmp.k=tmp.b=0;
139 if (cnt!=1) dfs_query(u,x,2,a[x],a[x]);
140 dfs_insert(u,x,1,tmp);
141 }
142 for (register int i=0;i<(int)e[x].size();i++)
143 {
144 int u=e[x][i];
145 if (vi[u]) continue;
146 dfs_size(u,x);
147 dfs_root(u,x,sz[u]);
148 divide(root);
149 }
150 }
151 signed main()
152 {
153 scanf("%lld",&n);
154 for (int i=1;i<n;i++)
155 {
156 int u,v;
157 scanf("%lld%lld",&u,&v);
158 e[u].push_back(v);
159 e[v].push_back(u);
160 }
161 for (int i=1;i<=n;i++)
162 {
163 scanf("%lld",&a[i]);
164 MAX=max(MAX,a[i]);
165 }
166 dfs_size(1,-1);
167 dfs_root(1,-1,sz[1]);
168 divide(root);
169 printf("%lld\n",MAX);
170 }

CF1303G Sum of Prefix Sums的更多相关文章

  1. [CF1303G] Sum of Prefix Sums - 点分治,李超线段树

    给定一棵 \(n\) 个点的带点权的树,求树上的路径 \(x_1,...,x_k\) ,最大化 \(\sum_{i=1}^k ia_{x_i}\) Solution 树上路径问题可用点分治. 考虑如何 ...

  2. Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)

    Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...

  3. CodeForces 837F - Prefix Sums | Educational Codeforces Round 26

    按tutorial打的我血崩,死活挂第四组- - 思路来自FXXL /* CodeForces 837F - Prefix Sums [ 二分,组合数 ] | Educational Codeforc ...

  4. Educational Codeforces Round 26 [ D. Round Subset ] [ E. Vasya's Function ] [ F. Prefix Sums ]

    PROBLEM D - Round Subset 题 OvO http://codeforces.com/contest/837/problem/D 837D 解 DP, dp[i][j]代表已经选择 ...

  5. 【题解】【数组】【Prefix Sums】【Codility】Genomic Range Query

    A non-empty zero-indexed string S is given. String S consists of N characters from the set of upper- ...

  6. 【题解】【数组】【Prefix Sums】【Codility】Passing Cars

    A non-empty zero-indexed array A consisting of N integers is given. The consecutive elements of arra ...

  7. Codeforces 837F Prefix Sums

    Prefix Sums 在 n >= 4时候直接暴力. n <= 4的时候二分加矩阵快速幂去check #include<bits/stdc++.h> #define LL l ...

  8. CodeForces 1204E"Natasha, Sasha and the Prefix Sums"(动态规划 or 组合数学--卡特兰数的应用)

    传送门 •参考资料 [1]:CF1204E Natasha, Sasha and the Prefix Sums(动态规划+组合数) •题意 由 n 个 1 和 m 个 -1 组成的 $C_{n+m} ...

  9. codeforces:Prefix Sums分析和实现

    题目大意: 给出一个函数P,P接受一个数组A作为参数,并返回一个新的数组B,且B.length = A.length + 1,B[i] = SUM(A[0], ..., A[i]).有一个无穷数组序列 ...

随机推荐

  1. 基于springboot工程浅谈整合rabbitmq怎么样防止消息发送mq不丢失和消费mq的消息防止丢失

    本文只针对springboot整合rabbitmq的消息防丢失,话不多说,上干货.... 设置发送mq消息不丢失实现思路 执行的方案: 第一步,要对队列,消息以及交换机进行持久化操作(保存到物理磁盘中 ...

  2. Python3基础——递归

    递归函数 如果一个函数在内部调用自身本身,这个函数就是递归函数. 递归函数的优点是定义简单,逻辑清晰.理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰. 使用递归函数需要注意防止栈 ...

  3. mysql插入数据报 (Incorrect string value: '\xB6\xFE' for column 'name' at row 1)

    这是我的表结构 mysql> describe students; +--------+---------------------+------+-----+---------+-------- ...

  4. Splay浅谈

    Splay是众多平衡树之一,它的功能十分强大,但常数极大.在LCT和许多数据结构中都能用到. Splay的核心操作,就是rotate.为了使树不是一条链,而是平衡的,我们需要旋转来维护形态.理论很简单 ...

  5. 101 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 05 通过方法实现学生类与专业类关联——方案二

    101 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 05 通过方法实现学生类与专业类关联--方案二 本文知识点:通过方法实现学生类与 ...

  6. Go path/filepath包

    path/filepath 标准库path中有的功能filepath全部具备, 所以使用filepath即可. isABS() 判断一个路径是不是绝对路径. package main import ( ...

  7. 达梦产品技术支持-DM8-数据库安装

    (该文档只适合个人环境搭建,未涉及到数据库的各种参数配置,未涉及到数据库规划,若需要企业环境搭建请咨询专业人员) 基于Windows的安装 windows下安装是图形化界面,与linux下的图形化界面 ...

  8. Python 3.9 新特性速览

    国庆假期,Python 社区发布了 3.9 版本的第一个 stable release. 相比于 3.8,Python 3.9 新特性众多,但不少特性与大多数 Python"使用者" ...

  9. Vue 全宇宙最浪 VSCode 配置、插件

    别人的那一堆配置.插件我就不写了- 首先进入官网下载并安装. 基本配置 在编译器 文件 >> 首选项 >> 设置,可以拷贝相面的选项后搜索相关配置 设置制表符等于空格数为 2: ...

  10. 用flannel实现跨主机container通信

    最近在看kubernetes,看到了网络部分,这部分是集群设计的难点,也是我比较感兴趣的部分.书上提到不同node的container之间通信主要使用flannel,openvswitch等技术,这些 ...