
牛客205089 牛妹的苹果树
发布日期:2021-05-06 15:23:24
浏览次数:19
分类:精选文章
本文共 3561 字,大约阅读时间需要 11 分钟。
一、题意
一棵n个点的带边权的树,q次询问,每次询问一个区间[l,r],求max(dist(u,v)),l≤u≤v≤r。
n,q都是3e5,边权是1e9。
二、题解
直径指的是带权直径。
需要发现一个性质,就是两个连续区间合并的时候,合并后的区间的直径的端点是合并前的四个端点中的两个。
通过枚举确定是哪两个。
st[i][j]表示[i,i+(1<<j)-1]的直径的端点。
预处理出st就可以在线回答询问了。
三、感受
不能随心所欲地乱写,要卡常。
(1)欧拉序求lca
(2)log2函数预处理
四、代码
#include#define pb push_back#define fi first#define se second#define sz(x) (int)x.size()#define cl(x) x.clear()#define all(x) x.begin() , x.end()#define rep(i , x , n) for(int i = x ; i <= n ; i ++)#define per(i , n , x) for(int i = n ; i >= x ; i --)#define mem0(x) memset(x , 0 , sizeof(x))#define mem_1(x) memset(x , -1 , sizeof(x))#define mem_inf(x) memset(x , 0x3f , sizeof(x))#define debug(x) cerr << #x << " = " << x << '\n'#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'#define ios std::ios::sync_with_stdio(false) , cin.tie(0)using namespace std ;typedef long long ll ;typedef long double ld ;typedef pair pii ;typedef pair pll ;const int mod = 998244353 ;const int maxn = 3e5 + 10 ;const int inf = 0x3f3f3f3f ;const double eps = 1e-6 ; mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ; int n , q ;int dep[maxn] ;ll d[maxn] ;pii st[maxn][25] ;vector g[maxn] ;void dfs1(int f , int u , int deep , ll dd){ dep[u] = deep ; d[u] = dd ; for(auto x : g[u]) { int v = x.fi ; int w = x.se ; if(v == f) continue ; dfs1(u , v , deep + 1 , dd + w) ; }}int cnt = 0 ;int a[maxn << 1] , pos[maxn] ;int f[maxn << 1][25] ;void dfs2(int fa , int u){ a[++ cnt] = u ; pos[u] = cnt ; for(auto x : g[u]) { int v = x.fi ; if(v == fa) continue ; dfs2(u , v) ; a[++ cnt] = u ; }}int lg[maxn << 1] ;void init1(){ lg[1] = 0; for (int i = 2; i <= cnt; i++) lg[i] = lg[i >> 1] + 1; rep(i , 1 , cnt) f[i][0] = a[i] ; rep(j , 1 , 20) rep(i , 1 , cnt - (1 << j)) if(dep[f[i][j - 1]] < dep[f[i + (1 << (j - 1))][j - 1]]) f[i][j] = f[i][j - 1] ; else f[i][j] = f[i + (1 << (j - 1))][j - 1] ;}int lca(int x , int y){ int ans ; if(pos[x] > pos[y]) swap(x , y) ; int l1 = pos[x] , l2 = pos[y] ; //int len = log2(l2 - l1 + 1) ; int len = lg[l2 - l1 + 1] ; if(dep[f[l1][len]] < dep[f[l2 - (1 << len) + 1][len]]) ans = f[l1][len] ; else ans = f[l2 - (1 << len) + 1][len] ; return ans ;}ll dis(int u , int v){ return d[u] + d[v] - 2ll * d[lca(u , v)] ;}pii t[15] ;pii merge(pii x , pii y){ int temp = 0 ; t[0] = {x.fi , x.se} ; t[1] = {y.fi , y.se} ; t[2] = {x.fi , y.fi} ; t[3] = {x.fi , y.se} ; t[4] = {x.se , y.fi} ; t[5] = {x.se , y.se} ; rep(i , 1 , 5) if(dis(t[i].fi , t[i].se) > dis(t[temp].fi , t[temp].se)) temp = i ; return t[temp] ;}void init(){ for(int i = 1 ; i <= n ; i ++) st[i][0] = {i , i} ; for(int j = 1 ; j <= 20 ; j ++) for(int i = 1 ; i + (1 << j) - 1 <= n ; i ++) st[i][j] = merge(st[i][j - 1] , st[i + (1 << (j - 1))][j - 1]) ;}void prework(){ dfs1(1 , 1 , 0 , 0) ; dfs2(1 , 1) ; init1() ; init() ;}pii query(int l , int r){ int len = lg[r - l + 1] ; return merge(st[l][len] , st[r - (1 << len) + 1][len]) ; }ll solve(int l , int r){ pii ans = query(l , r) ; return dis(ans.fi , ans.se) ;}int main(){ ios ; cin >> n >> q ; rep(i , 1 , n - 1) { int u , v , w ; cin >> u >> v >> w ; g[u].pb({v , w}) ; g[v].pb({u , w}) ; } prework() ; while(q --) { int l , r ; cin >> l >> r ; cout << solve(l , r) << '\n' ; } return 0 ;}
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年03月24日 15时56分27秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
SQL 强化练习 (四)
2021-05-09
Excel 拼接为 SQL 并打包 exe
2021-05-09
Pandas数据分析从放弃到入门
2021-05-09
Matplotlib绘制漫威英雄战力图,带你飞起来!
2021-05-09
机器学习是什么
2021-05-09
《小王子》里一些后知后觉的道理
2021-05-09
《自私的基因》总结
2021-05-09
《山海经》总结
2021-05-09
《非暴力沟通》总结
2021-05-09
《你当像鸟飞往你的山》总结
2021-05-09
《我是猫》总结
2021-05-09
《抗糖化书》总结
2021-05-09
apache虚拟主机配置
2021-05-09
光盘作为yum源
2021-05-09
PHP 正则表达式资料
2021-05-09
PHP官方网站及PHP手册
2021-05-09
mcrypt加密以及解密过程
2021-05-09
mysql连续聚合
2021-05-09
go等待N个线程完成操作总结
2021-05-09
消息队列 RocketMQ 并发量十万级
2021-05-09