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> ...
随机推荐
- JavaScript高级程序编程(三)
2017-06-24 更新 北京连续三天下雨啦 乘性操作符 1.ECMA中定义了三种操作符,乘法 除法 和求模 并与其他语言相应操作符相同,再计算之前如果不是数值,会先去调用number()方法转 ...
- 基于Linux(中标麒麟)上QT的环境搭建——解决cannot find lGL的问题
接上一篇,QT在中标麒麟环境安装完成后遇到运行报错的问题 一.问题描述: 在中标麒麟上配置好QT的环境后,新建一个工程,不做其他的任何操作,直接运行都会报cannot find lGL的错误.如图所示 ...
- 无法定位程序输入点到xxx.dll
Q:安装pytorch时报错无法定位程序输入点到Anaconda3\Library\bin\libssl-1_1-x64.dll A:下载libssl-1_1-x64.dll覆盖bin下的文件 下载地 ...
- linux性能监控常用命令
概述 我们在linux下,如果想要监控服务器性能.我们必须掌握以下常用的指标查看命令. ps pstree top free vmstat sar ps ps命令能给出当前系统中进程的快照.下面我们列 ...
- Linux安装问题解决
首先安装VM,之后下载centos7.5 安装好vm后运行时无法执行操作 提示 已将该虚拟机配置为使用 64 位客户机操作系统.但是,无法执行 64 位操作. 此主机支持 Intel VT-x,但 I ...
- BASE64使用场景
BASE64使用场景 Base64就是一种基于64个可打印字符来表示二进制数据的方法. Base64编码是从二进制到字符的过程. 在项目中,将报文进行压缩.加密后,最后一步必然是使用base64编码, ...
- Spark2.x(五十六):Queue's AM resource limit exceeded.
背景: 按照业务需求将数据拆分为60份,启动60个application分别运行对每一份数据,application的提交脚本如下: #/bin/sh #LANG=zh_CN.utf8 #export ...
- locust参数化(数据库取值)
locust参数化(数据库取值) 基于上一篇参数化的梳理,本篇用另一种方法从数据库中取出这100个用户来登录 思路:在 TaskSet 中的 on_start 方法表示执行任务前的操作,可以将数据库取 ...
- EasyUi datagrid列表增加复选框
本文为博主原创,未经允许不得转载 1.增加复选框列 { field: 'oid', title: '<input type=\"checkbox\" name ...
- docker安装并运行ngnix
拉取nginx最新版本的镜像: [mall@VM_0_7_centos ~]$ sudo docker pull nginx:latest [sudo] password for mall: late ...