Codechef TSUM2 Sum on Tree 点分治、李超线段树
点分治模板题都不会迟早要完
发现这道题需要统计所有路径的信息,考虑点分治统计路径信息。
点分治之后,因为路径是有向的,所以对于每一条路径都有向上和向下的两种。那么如果一条向上的路径,点数为\(s_1\),单独考虑这条路径的权值和为\(v_1\),和一条向下的路径,点权和为\(s_2\),单独考虑这条路径的权值和为\(v_2\),这两条路径进行拼接(分治中心算在向上路径中,这样\(s_1 > 0\)),那么拼接起来的路径的权值和就是\(s_1s_2 + v_1 + v_2\)。如果我们枚举到了一条向上的路径,对于每一条向下路径能够和这条向上路径拼接产生的贡献是一个一次函数的形式,同时横坐标范围在\(1\)到\(50000\)之间,所以可以使用李超线段树维护最值。
注意到来自同一棵子树的向上和向下路径不能拼接,所以对于每一棵子树,先把子树内所有向上路径统计完成,再把向下的路径放进李超树,从前往后做一遍再从后往前做一遍即可。
注意一下分治中心单独作为一条向上路径/向下路径为空的情况。
#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;
int read(){
int a = 0; char c = getchar(); bool f = 0;
while(!isdigit(c)){f = c == '-'; c = getchar();}
while(isdigit(c)){a = a * 10 + c - 48; c = getchar();}
return f ? -a : a;
}
const int _ = 100003;
#define int long long
struct line{
int k , b;
line(int _k = -1e9 , int _b = -1e18) : k(_k) , b(_b){}
};
long double sect(line a , line b){return 1.0 * (b.b - a.b) / (a.k - b.k);}
namespace Tree{
line now[_ << 2];
#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)
void init(int x , int l , int r){
if(now[x].k != -1e9 || now[x].b != -1e18){
now[x] = line();
if(l != r){init(lch , l , mid); init(rch , mid + 1 , r);}
}
}
void ins(int x , int l , int r , line p){
line q = now[x];
if(q.k == p.k){now[x] = q.b > p.b ? q : p; return;}
if(p.k > q.k) swap(p , q);
long double t = sect(p , q);
if(t <= l){now[x] = q; return;}
if(t >= r){now[x] = p; return;}
if(t <= mid){
now[x] = q;
if(l != r) ins(lch , l , mid , p);
}
else{
now[x] = p;
if(l != r) ins(rch , mid + 1 , r , q);
}
}
int calc(line A , int x){return A.k * x + A.b;}
int qry(int x , int l , int r , int tar){
if(l == r) return calc(now[x] , tar);
return max(calc(now[x] , tar) , mid >= tar ? qry(lch , l , mid , tar) : qry(rch , mid + 1 , r , tar));
}
}
struct Edge{
int end , upEd;
}Ed[_ << 1];
int head[_] , val[_] , cntEd , N , mnsz , mnid , nowsz , ans;
bool vis[_];
void addEd(int a , int b){
Ed[++cntEd] = (Edge){b , head[a]};
head[a] = cntEd;
}
void getsz(int x){
vis[x] = 1; ++nowsz;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]) getsz(Ed[i].end);
vis[x] = 0;
}
int getrt(int x){
int sz = 1 , mx = 1; vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
int t = getrt(Ed[i].end);
mx = max(mx , t); sz += t;
}
mx = max(mx , nowsz - sz);
if(mx < mnsz){mnsz = mx; mnid = x;}
vis[x] = 0; return sz;
}
void dfs1(int x , int sum , int sz , int v){
ans = max(ans , Tree::qry(1 , 1 , N , sz) + sum);
vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]) dfs1(Ed[i].end , sum + val[Ed[i].end] + v , sz + 1 , val[Ed[i].end] + v);
vis[x] = 0;
}
void dfs2(int x , int sum , int sz , int v){
Tree::ins(1 , 1 , N , line(v , sum));
vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]) dfs2(Ed[i].end , sum + (sz + 1) * val[Ed[i].end] , sz + 1 , val[Ed[i].end] + v);
vis[x] = 0;
}
void solve(int x){
mnsz = 1e9; nowsz = 0;
getsz(x); getrt(x); vis[x = mnid] = 1;
Tree::init(1 , 1 , N); Tree::ins(1 , 1 , N , line(0 , 0));
vector < int > nxt;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
nxt.push_back(Ed[i].end);
dfs1(Ed[i].end , 2 * val[x] + val[Ed[i].end] , 2 , val[x] + val[Ed[i].end]);
dfs2(Ed[i].end , val[Ed[i].end] , 1 , val[Ed[i].end]);
}
ans = max(ans , Tree::qry(1 , 1 , N , 1) + val[x]); Tree::init(1 , 1 , N);
reverse(nxt.begin() , nxt.end());
for(auto t : nxt){
dfs1(t , 2 * val[x] + val[t] , 2 , val[x] + val[t]);
dfs2(t , val[t] , 1 , val[t]);
}
for(auto t : nxt) solve(t);
}
signed main(){
for(int T = read() ; T ; --T){
N = read(); cntEd = 0; ans = -1e18;
memset(vis , 0 , sizeof(bool) * (N + 1));
memset(head , 0 , sizeof(int) * (N + 1));
for(int i = 1 ; i <= N ; ++i) val[i] = read();
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read(); addEd(a , b); addEd(b , a);
}
solve(1); printf("%lld\n" , ans);
}
return 0;
}
Codechef TSUM2 Sum on Tree 点分治、李超线段树的更多相关文章
- [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\) 并将路径分为经过重心和不 ...
- [CodeChef - STREETTA] The Street 李超线段树
大致题意: 给出两个序列A,B,A初始为负无穷,B初始为0,有三种操作 1.在A上区间[u,v]上加一个等差数列,取与原本A序列的最大值. 2.在B上区间[u,v]上加一个等差数列. 3.给出一个点X ...
- 【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 ...
- 【BZOJ-1568】Blue Mary开公司 李超线段树 (标记永久化)
1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 557 Solved: 192[Submit ...
- Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)
听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ... 题意 给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) . 从 \( ...
- Luogu P4097 [HEOI2013]Segment 李超线段树
题目链接 \(Click\) \(Here\) 李超线段树的模板.但是因为我实在太\(Naive\)了,想象不到实现方法. 看代码就能懂的东西,放在这里用于复习. #include <bits/ ...
- BZOJ 3165 李超线段树
思路: 李超线段树 我是把线段转成斜率的形式搞得 不知道有没有更简单的方法 //By SiriusRen #include <cmath> #include <cstdio> ...
随机推荐
- LOJ6609 无意识的石子堆【加强版】【容斥原理,计数】
题目描述:在一个\(n\times m\)的网格中,放\(2n\)个棋子,使每一行和每一列都不超过两个棋子.求方案数\(\mathrm{mod} \ 943718401\). 数据范围:\(n\le ...
- SpringSecurity的简单入门
以下是大体思路 1.导入坐标 <properties> <spring.version>4.2.4.RELEASE</spring.version> </pr ...
- node.js之客户端发起https和http请求
应用场景:1.VsCode插件开发(主要针对以javascript为主的vscode插件);2.使用Node.js开发的客户端程序 Node.js之http请求(客户端) 代码示例如下: var ht ...
- golang 文件传输小demo(转载)
转载地址:https://www.cnblogs.com/qq702368956/p/10195497.html 获取文件信息需要用到os. Stat接口,发送文件前开启接收者(服务端),启动客户端先 ...
- Runtime Only和Runtime + Compiler
如果你需要在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),就将需要加上编译器,即完整版 当使用 vue-loader ...
- 对snapshot isolation和write-snapshot isolation的一些思考
数据库中存在读异常和写异常. 所谓snapshot,目的在于保证事务执行的各个阶段,读相同的数据项得到的结果没有变化,这样一来就避免了不可重复读.幻读等读数据异常. 但是仅仅是读数据不变还不够,因为这 ...
- 剑指offer: 求1+2+...+n
题目描述: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 思路分析: 由于题目的限制条件很多.同样想到 ...
- .Net Core NOPI操作word(一)
NOPI使用方式 1.安装nuget包 即可使用 Install-Package NPOI 一.创建word文档 //创建生成word文档 string path = "D:\\test.d ...
- 第2课第7节_Java面向对象编程_内部类_P【学习笔记】
摘要:韦东山android视频学习笔记 1.什么是内部类:在类的内部定义一个类,内部类可以访问类的私有属性 class Outer{ ; class Inner{ public void print ...
- rk3288 usb无线网卡支持 8188eu
第一部分是kernel 内核配置参考rk文档,把device driver 下wireless相关的先勾选上. 编译到buildin有问题,识别不到,所以打算编译成ko cd kernel/driv ...