Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)
个人感觉这题称不上毒瘤。
首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不经过重心两类路径。对于第二类路径我们肯定可以在对 \(r\) 所有子树进一步分治的过程中将其变成第一类路径,因此我们只用考虑怎样计算第一类路径的贡献即可。
显然对于一条第一类路径 \(x\to y\),我们要将其拆成 \(x\to r\) 和 \(r\to y\) 两部分分别处理,考虑怎样合并这两部分的贡献,我们记 \(dep_x\) 为 \(x\to r\) 路径上点的个数,\(sum_x\) 表示 \(x\to r\) 上所有点的权值之和,那么对于 \(x\to r\) 上某个点 \(z\) 而言,它对和的贡献即为 \((dep_x-dep_z+1)\times a_z\),同理对于 \(r\to y\) 上某个点 \(z\),它对和的贡献即为 \((dep_x-1+dep_z)\times a_z\),那么我们考虑再设一个 \(sum1_x\) 表示 \(x\to r\) 路径上所有点的 \((dep_x-dep_z+1)\times a_z\),\(sum2_x\) 表示 \(x\to r\) 路径上所有点的 \(dep_z\times a_z\) 之和。对于 \(x\) 的某个儿子 \(y\),显然有 \(sum1_y=sum1_x+sum_y,sum2_y=sum2_x+dep_ya_y\)。
因此上面 \(x\to y\) 路径的权值就可以写作 \(sum1_x+(dep_x-1)sum_y+sum2_y\),但注意到 \(r\) 既在 \(x\to r\) 的路径上也在 \(r\to y\) 的路径上,它的贡献被计算了两次,因此需减去 \(dep_xa_r\),得到 \(sum1_x+(dep_x-1)sum_y+sum2_y-dep_xa_r\),考虑怎样快速维护这个东西,我们显然要枚举 \(x,y\) 中的一个并快速维护另一个变量的决策,那么我们枚举什么好呢?注意到如果我们枚举 \(y\),那么我们相当于求若干条形如 \(f_x(t)=(dep_x-1)t+sum1_x-dep_xa_r\) 的直线在 \(t=sum_y\) 处的最大值,而 \(sum_y\) 的值域过大不好直接李超线段树,要写个动态凸壳,过于毒瘤,因此考虑枚举 \(x\),这样相当于我们要求若干条形如 \(f_y(t)=sum_y·t+sum2_y\) 的直线在 \(t=dep_x-1\) 处的最大值,这个值域是在 \([0,n-1]\) 范围内的,就可以李超线段树维护了。
算下复杂度,点分 1log,李超线段树全局插入是 1log 的,因此总复杂度 2log,可以通过此题。
最后说几个注意点:
- 在点分治过程中注意要正反各跑一遍,因为假设按顺序枚举的子树依次是 \(t_1,t_2,\cdots,t_m\),那么对于某个 \(i<j\),有可能是 \(x\in t_i,y\in t_j\),也有可能 \(x\in t_j,y\in t_i\)。
- 每次点分完一个点后要清空李超树,但重新建树复杂度过高,因此可以考虑将修改的点记录在一个
std::vector中每次将vector中的点的最大优势线段赋为空即可。
const int MAXN=1.5e5;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,a[MAXN+5],hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
struct line{
ll k,b;
line(ll _k=0,ll _b=-INF):k(_k),b(_b){}
ll get(int x){return 1ll*k*x+b;}
};
struct node{int l,r;line v;} s[MAXN*4+5];
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r) return;
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
vector<int> opts;
void modify(int k,line v){
int mid=s[k].l+s[k].r>>1;
ll l1=s[k].v.get(s[k].l),r1=s[k].v.get(s[k].r),m1=s[k].v.get(mid);
ll l2=v.get(s[k].l),r2=v.get(s[k].r),m2=v.get(mid);
if(l1>=l2&&r1>=r2) return;
if(l2>=l1&&r2>=r1) return s[k].v=v,opts.pb(k),void();
if(m2>=m1){
if(l2<l1) return modify(k<<1,s[k].v),s[k].v=v,void();
else return modify(k<<1|1,s[k].v),s[k].v=v,void();
} else {
if(l2<l1) return modify(k<<1|1,v),void();
else return modify(k<<1,v),void();
}
}
ll query(int k,int x){
if(s[k].l==s[k].r) return s[k].v.get(x);int mid=s[k].l+s[k].r>>1;
return max(s[k].v.get(x),(x<=mid)?query(k<<1,x):query(k<<1|1,x));
}
bool vis[MAXN+5];int siz[MAXN+5],mx[MAXN+5],cent=0,subsiz[MAXN+5];
ll ans=0,sum[MAXN+5],_sum[MAXN+5],__sum[MAXN+5];int dep[MAXN+5];
void findcent(int x,int f,int tot){
siz[x]=1;mx[x]=0;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
findcent(y,x,tot);siz[x]+=siz[y];
chkmax(mx[x],siz[y]);
} chkmax(mx[x],tot-siz[x]);
if(mx[x]<mx[cent]) cent=x;
}
vector<int> pts;
void getdis(int x,int f){
pts.pb(x);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
dep[y]=dep[x]+1;sum[y]=sum[x]+a[y];
_sum[y]=_sum[x]+sum[y];
__sum[y]=__sum[x]+1ll*a[y]*dep[y];
getdis(y,x);
}
}
void divcent(int x){
vis[x]=1;chkmax(ans,a[x]);dep[x]=1;
sum[x]=_sum[x]=__sum[x]=a[x];
modify(1,line(sum[x],__sum[x]));
stack<int> stk;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(vis[y]) continue;
sum[y]=sum[x]+a[y];dep[y]=2;
_sum[y]=sum[x]+a[x]+a[y];
__sum[y]=sum[x]+(a[y]<<1);
pts.clear();getdis(y,x);subsiz[y]=pts.size();
for(int i=0;i<pts.size();i++){
int z=pts[i];
chkmax(ans,_sum[z]+query(1,dep[z]-1)-1ll*a[x]*dep[z]);
}
for(int i=0;i<pts.size();i++){
int z=pts[i];
modify(1,line(sum[z],__sum[z]));
} stk.push(y);
}
for(int i=0;i<opts.size();i++) s[opts[i]].v=line();
opts.clear();
while(!stk.empty()){
int y=stk.top();stk.pop();
pts.clear();getdis(y,x);
for(int i=0;i<pts.size();i++){
int z=pts[i];
chkmax(ans,_sum[z]+query(1,dep[z]-1)-1ll*a[x]*dep[z]);
}
for(int i=0;i<pts.size();i++){
int z=pts[i];
modify(1,line(sum[z],__sum[z]));
}
} chkmax(ans,_sum[x]+query(1,0)-a[x]);
for(int i=0;i<opts.size();i++) s[opts[i]].v=line();
opts.clear();
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(vis[y]) continue;
cent=0;findcent(y,x,subsiz[y]);
divcent(cent);
}
}
int main(){
scanf("%d",&n);mx[0]=1e9;build(1,0,n);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
findcent(1,0,n);divcent(cent);printf("%lld\n",ans);
return 0;
}
Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)的更多相关文章
- [CF1303G] Sum of Prefix Sums - 点分治,李超线段树
给定一棵 \(n\) 个点的带点权的树,求树上的路径 \(x_1,...,x_k\) ,最大化 \(\sum_{i=1}^k ia_{x_i}\) Solution 树上路径问题可用点分治. 考虑如何 ...
- CF1303G Sum of Prefix Sums
点分治+李超树 因为题目要求的是树上所有路径,所以用点分治维护 因为在点分治的过程中相当于将树上经过当前$root$的一条路径分成了两段 那么先考虑如何计算两个数组合并后的答案 记数组$a$,$b$, ...
- Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)
听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ... 题意 给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) . 从 \( ...
- Codechef TSUM2 Sum on Tree 点分治、李超线段树
传送门 点分治模板题都不会迟早要完 发现这道题需要统计所有路径的信息,考虑点分治统计路径信息. 点分治之后,因为路径是有向的,所以对于每一条路径都有向上和向下的两种.那么如果一条向上的路径,点数为\( ...
- Codeforces 1175G Yet Another Partiton Problem [DP,李超线段树]
Codeforces 思路 首先吐槽一句:partiton是个什么东西?我好像在百度翻译里面搜不到呀qwq 发现不了什么性质,那就直接上DP吧.注意到DP可以分层,所以设\(dp_i\)表示当前层,分 ...
- Codeforces 1175G - Yet Another Partiton Problem(李超线段树)
Codeforces 题面传送门 & 洛谷题面传送门 这是一道李超线段树的毒瘤题. 首先我们可以想到一个非常 trivial 的 DP:\(dp_{i,j}\) 表示前 \(i\) 个数划 ...
- 李超线段树(segment[HEOI2013]-洛谷T4097)
(neng了好久好久才糊弄懂得知识点...) 一.李超线段树 在线动态维护一个二维平面直角坐标系, 支持插入一条线段, 询问与直线x = x0相交的所有线段中,交点y的最大/小值 (若有多条线段符合条 ...
- 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交
4515: [Sdoi2016]游戏 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 304 Solved: 129[Submit][Status][ ...
- 【BZOJ-3165】Segment 李超线段树(标记永久化)
3165: [Heoi2013]Segment Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 368 Solved: 148[Submit][Sta ...
随机推荐
- 使用vue-cli+webpack搭建vue开发环境
在这里我真的很开心,好久没有用过博客,今天突然看到了我的博客有不少人看过,虽然没有留下脚印,但是还是激起了我重新拿起博客的信心,感谢大家. 在这里我们需要首先下载node,因为我们要用到npm包下载, ...
- 第七次Scrum Metting
日期:2021年5月5日 会议主要内容概述:前后端对接,以及接下来的测试优化等工作. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 测试数据模块和 ...
- STM32采集AD的输入阻抗问题
在做一款消费电子产品时,需要采集电池电压(3.3V-4.2V),同时在休眠的时候希望尽量减小待机电流.电池电压采集电路采用两个1%的300K电阻进行分压,由该电路引起的待机电路为4.2/(300+30 ...
- MySQL实战优化之InnoDB整体架构
一.InnoDB 更新数据得整体架构 每个组件的作用说明: 用一条更新数据来说明每个主键得作用: update student set name = 'zhangsan' where id = 10 ...
- shell 匿名管道和命名管道
管道的特点:如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作:同理,写入管道的操作如果没有读取管道的操作,这一动作也会滞留. 1,匿名管道 匿名管道使用 ...
- 字符串压缩 牛客网 程序员面试金典 C++ Python
字符串压缩 牛客网 程序员面试金典 C++ Python 题目描述 利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能.比如,字符串"aabcccccaaa"经压缩会变 ...
- JS基础面试
1. JS是高级语言弱类型语言 脚本语言 1.1高级语言我们写完的代码不能直接执行,要先经过js引擎翻译成0101这种机器语言才能执行 1.2 弱类型语言变量可以在前一行设置为一个数字,下一行修改为一 ...
- CSS 盒子的边距塌陷
tip:为能更直观地学习,本文章已省略部分 css 样式代码. 我相信下面的情形大家在日常工作中常常碰到:在制作静态页面中,为了页面整体的协调与美观,我们想让子盒子 image-div 的上边沿距离父 ...
- Arthas在线java进程诊断工具 在线调试神器
tag: java 诊断 堆栈 在线调试 耗时 死锁 arthas 阿里巴巴 Arthas (阿尔萨斯) Arthas 是 Alibaba 开源的Java诊断工具,深受开发者喜爱. 官网文档:http ...
- 前端需要了解的颜色模型,RGB、HSL和HSV
颜色模型,是用来表示颜色的数学模型.比如最常见的 RGB模型,使用 红绿蓝 三色来表示颜色. 一般的颜色模型,可以按照如下分类: 面向硬件设备的颜色模型:RGB,CMYK,YCrCb. 面向视觉感知的 ...