CF1303G Sum of Prefix Sums
点分治+李超树
因为题目要求的是树上所有路径,所以用点分治维护
因为在点分治的过程中相当于将树上经过当前$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的更多相关文章
- [CF1303G] Sum of Prefix Sums - 点分治,李超线段树
给定一棵 \(n\) 个点的带点权的树,求树上的路径 \(x_1,...,x_k\) ,最大化 \(\sum_{i=1}^k ia_{x_i}\) Solution 树上路径问题可用点分治. 考虑如何 ...
- Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)
Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...
- CodeForces 837F - Prefix Sums | Educational Codeforces Round 26
按tutorial打的我血崩,死活挂第四组- - 思路来自FXXL /* CodeForces 837F - Prefix Sums [ 二分,组合数 ] | Educational Codeforc ...
- 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]代表已经选择 ...
- 【题解】【数组】【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- ...
- 【题解】【数组】【Prefix Sums】【Codility】Passing Cars
A non-empty zero-indexed array A consisting of N integers is given. The consecutive elements of arra ...
- Codeforces 837F Prefix Sums
Prefix Sums 在 n >= 4时候直接暴力. n <= 4的时候二分加矩阵快速幂去check #include<bits/stdc++.h> #define LL l ...
- CodeForces 1204E"Natasha, Sasha and the Prefix Sums"(动态规划 or 组合数学--卡特兰数的应用)
传送门 •参考资料 [1]:CF1204E Natasha, Sasha and the Prefix Sums(动态规划+组合数) •题意 由 n 个 1 和 m 个 -1 组成的 $C_{n+m} ...
- codeforces:Prefix Sums分析和实现
题目大意: 给出一个函数P,P接受一个数组A作为参数,并返回一个新的数组B,且B.length = A.length + 1,B[i] = SUM(A[0], ..., A[i]).有一个无穷数组序列 ...
随机推荐
- CString类常用方法----Left(),Mid(),Right()
参考:https://blog.csdn.net/Qingqinglanghua/article/details/4992624 CString Left( int nCount ) const; ...
- c语言gets函数
函数gets的原型为:char*gets(char*buffer); 在 stdio.h中定义,如果要程序中用到此函数需包含#include<stdio.h> gets()函数用来从标准输 ...
- Cisco思科模拟器 交换机IP地址的配置 入门详解 - 精简归纳
Cisco思科模拟器 交换机IP地址的配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 10 / 10 转载请注明出处!️ 目录 Cisco思科模拟器 交换机IP地址的配置 入门详解 ...
- ORA-28001: the password has expired 密码已过期
ORA-28001: the password has expiredORA-28001: 密码已过期 Cause: The user's account has expired and ...
- dockerfile解析过程
什么是dockerfile? DockerFile是用来构建docker镜像的文件,是由一系列命令和参数组成. 构建步骤? 1.编写dockerfile文件 2.docker build 3.dock ...
- 测试AAA
程序计数器(线程私有) 程序计数器(Program Counter Register),也有称作为 PC 寄存器.保存的是程序当 前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当 ...
- 阿里百秀后台管理项目笔记 ---- Day01
摘要 在此记录一下阿里百秀项目的教学视频的学习笔记,部分页面被我修改了,某些页面效果会不一样,基本操作是一致的,好记性不如烂笔头,加油叭!!! step 1 : 整合全部静态页面 将静态页面全部拷贝到 ...
- 一文看懂Vue3.0的优化
1.源码优化: a.使用monorepo来管理源码 Vue.js 2.x 的源码托管在 src 目录,然后依据功能拆分出了 compiler(模板编译的相关代码).core(与平台无关的通用运行时代码 ...
- Socket编程,C语言版!
socket编程--send函数&recv函数详解 一.send函数 ✍ 函数原型: int send( SOCKET s,char *buf,int len,int flags ); ✍ 功 ...
- centos8平台redis cluster集群添加/删除node节点(redis5.0.7)
一,当前redis cluster的node情况: 我们的添加删除等操作都是以这个cluster作为demo cluster采用六台redis,3主3从 redis1 : ip: 172.17.0.2 ...