传送门


点分治模板题都不会迟早要完

发现这道题需要统计所有路径的信息,考虑点分治统计路径信息。

点分治之后,因为路径是有向的,所以对于每一条路径都有向上和向下的两种。那么如果一条向上的路径,点数为\(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 点分治、李超线段树的更多相关文章

  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. [CodeChef - STREETTA] The Street 李超线段树

    大致题意: 给出两个序列A,B,A初始为负无穷,B初始为0,有三种操作 1.在A上区间[u,v]上加一个等差数列,取与原本A序列的最大值. 2.在B上区间[u,v]上加一个等差数列. 3.给出一个点X ...

  4. 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交

    4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 129[Submit][Status][ ...

  5. 【BZOJ-3165】Segment 李超线段树(标记永久化)

    3165: [Heoi2013]Segment Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 368  Solved: 148[Submit][Sta ...

  6. 【BZOJ-1568】Blue Mary开公司 李超线段树 (标记永久化)

    1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 557  Solved: 192[Submit ...

  7. Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)

    听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ... 题意 给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) . 从 \( ...

  8. Luogu P4097 [HEOI2013]Segment 李超线段树

    题目链接 \(Click\) \(Here\) 李超线段树的模板.但是因为我实在太\(Naive\)了,想象不到实现方法. 看代码就能懂的东西,放在这里用于复习. #include <bits/ ...

  9. BZOJ 3165 李超线段树

    思路: 李超线段树 我是把线段转成斜率的形式搞得 不知道有没有更简单的方法 //By SiriusRen #include <cmath> #include <cstdio> ...

随机推荐

  1. 洛谷 P2813【母舰】 题解

    总体思路: 输入护盾和攻击力,然后快速排序sort走起来, 排完序之后从第一个开始找,如果攻击力大于护盾,护盾继续下一个, 这个攻击力记录为0,如果小雨的话,那就攻击力继续下一个,护盾不动, 其中最为 ...

  2. THUWC2020 划船记

    PS:THUWC2020在2019年 Day 1 考场外的太懒了不写了. 三题题目大意: T1: T2: 给定一个\(n(\leq 10^5)\)个结点的有向图,每条边有个limit,表示经过这条边l ...

  3. 第07组 Beta冲刺(3/5)

    队名:摇光 队长:杨明哲 组长博客:求戳 作业博客:求再戳 队长:杨明哲 过去两天完成了哪些任务 文字/口头描述:代码编辑器,目前没什么进展 展示GitHub当日代码/文档签入记录:(组内共用,已询问 ...

  4. log4net 控制台和文件和数据库输出三种方式

    1.新建console应用项目SendEvaluateDataToProvinceConsole 2.选择SendEvaluateDataToProvinceConsole项目右键 选择 管理NuGe ...

  5. 微信小程序实例:分享给一个人还是分享到群的判断代码

    微信小程序的分享功能,在最新版库的ide上已经不能拿到分享回调了,官方api也删除了对应的回调函数,看样子是砍掉了,不过真机测试还是可以的,话不多说,上代码: /* // 分享功能回调 onLoad: ...

  6. JMeter压测“java.net.SocketException: Socket closed”解决方法 - Andrea-Pirlo

    报错详情: 引起 java.net.SocketException: Socket closed 错误的原因通常是 未设置连接的超时时间. 解决方法: 该问题可以尝试通过以下方法解决. 如果在 HTT ...

  7. 【Java】Spring之面向方面编程(AOP)(五)

    面向方面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP).OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面.方面实现了跨越多种类型和对象的关注点(例如事务管理)的 ...

  8. [IR] Inverted Index & Boolean retrieval

    教材:<信息检索导论> 倒排索引 How to build Inverted Index? 1. Token sequence. 2. Sort by terms. 3. Dictiona ...

  9. LODOP一个任务多列,只打一列如何维护

    打印维护是针对整个任务进行维护的,打印多少个打印项就要维护多少个打印项,维护了多少打印项,就要打印多少内容.但是打印的时候不需要打印其他列,可以把其他列的数值传入空置,add_print_text纯文 ...

  10. [LeetCode] 297. Serialize and Deserialize Binary Tree 二叉树的序列化和反序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...