• P4565 [CTSC2018]暴力写挂(边分树)


    P4565 [CTSC2018]暴力写挂(边分树)

    题目大意

    给定两棵树,边有权,求下式的最大值

    [mathrm{depth}(x) + mathrm{depth}(y) - ({mathrm{depth}(mathrm{LCA}(x,y))}+{mathrm{depth'}(mathrm{LCA'}(x,y))}) ]

    数据范围

    对于所有数据, (n le 366666 , |v| le 2017011328) 。 详细数据范围见下表,表格中的“无” 表示无特殊限制。

    测试点编号 (n le) v T 是一条链 T' 是一条链
    1 36 =1
    2 366 =1
    3 1388 >0
    4 1999 >0
    5 2666 >0
    6 5666
    7 8666
    8 11111
    9 12345
    10 366666 >0
    11 366666
    12~13 366666 >0
    14 366666
    15~16 366666 >0
    17 366666
    18~20 366666

    (depth(p)) 和 $depth'(p) $分别表示树 (T)(T') 中点 (1) 到点 (p) 的距离,这里规定,距离指的是经过的边的边权总和,其中 (mathrm{depth}(1) = 0)
    (LCA(x, y))(LCA'(x, y)) 分别表示树 (T)(T') 中点 (x) 与点 (y) 的最近公共祖先,即在从 (x)(y) 的最短路径上的距离根经过边数最少的点

    解题思路

    边分树合并模板题,主要是一些细节

    这个式子我们可以化为(其实不化也可做)

    [Ans = frac 12 max(dis(x, y)+dep(x)+dep(y)-2*dep'(lca'(x,y))) ]

    考虑在第二棵树上枚举 lca,同时边分治合并统计前半部分的最大值,主要还是一些细节和实现方式

    可以考虑使用 namespace 肆意使用重复的变量名

    代码

    const int N = 400250;
    struct Tree {
    	int ls, rs;
    	ll vl, vr;
    	Tree() { vl = vr = -1e15; }
    	#define ls(p) tree[p].ls
    	#define rs(p) tree[p].rs
    	#define vl(p) tree[p].vl
    	#define vr(p) tree[p].vr
    }tree[N<<5];
    
    int rt[N], las[N], nodecnt;
    namespace Conquer {
    	const int N = 1500005;
    	int h[N], ne[N<<1], to[N<<1]; ll w[N<<1], dis[N], tot = 1, cnt;
    	inline void add(int x, int y, ll z) {
    		ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z;
    	}
    	inline void adde(int x, int y, ll z) { add(x, y, z), add(y, x, z); }
    	void get_dis(int x, int fa) {
    		for (int i = h[x], y; i; i = ne[i])
    			if ((y = to[i]) != fa)
    				dis[y] = dis[x] + w[i], get_dis(y, x);
    	}
    	
    	int vis[N], siz[N], Siz, lim, ed, n;
    	void get(int x, int fa) {
    		siz[x] = 1;
    		for (int i = h[x], y; i; i = ne[i]) {
    			if ((y = to[i]) == fa || vis[i]) continue;
    			get(y, x), siz[x] += siz[y];
    			int tp = max(siz[y], Siz - siz[y]);
    			if (tp < lim) lim = tp, ed = i;
    		}
    	}
    	void dfs(int x, int fa, ll Dis, bool tp) {
    		if (x <= n) {
    			++nodecnt;
    			if (ls(las[x]) == -1) ls(las[x]) = nodecnt;
    			else rs(las[x]) = nodecnt;
    			if (!tp) ls(nodecnt) = -1, vl(nodecnt) = Dis + dis[x];
    			else rs(nodecnt) = -1, vr(nodecnt) = Dis + dis[x];
    			las[x] = nodecnt;
    		}
    		for (int i = h[x], y; i; i = ne[i]) 
    			if ((y = to[i]) != fa && !vis[i]) 
    				dfs(y, x, Dis + w[i], tp);
    	}
    	void conquer(int x, int S) {
    		if (S <= 1) return; Siz = lim = S, get(x, 0);
    		vis[ed] = vis[ed^1] = 1; int tx = to[ed], ty = to[ed^1];
    		dfs(tx, 0, 0, 0), dfs(ty, 0, w[ed], 1);
    		conquer(ty, S - siz[tx]), conquer(tx, siz[tx]);
    	}
    	
    	void main() {
    		for (int i = 1;i <= n; i++)
    			rt[i] = las[i] = ++nodecnt, ls(rt[i]) = -1;
    		get_dis(1, 0), conquer(1, cnt);
    	}
    }
    
    namespace T2 {
    	int h[N], ne[N<<1], to[N<<1]; ll w[N<<1], tot;
    	inline void add(int x, int y, ll z) {
    		ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z;
    	}
    	ll ans, now;
    	int merge(int x, int y) {
    		if (!x || !y) return x | y;
    		Mx(ans, max(vl(x) + vr(y), vr(x) + vl(y)) - now);
    		ls(x) = merge(ls(x), ls(y));
    		rs(x) = merge(rs(x), rs(y));
    		Mx(vl(x), vl(y)), Mx(vr(x), vr(y));
    		return x;
    	}
    	void dfs(int x, int fa, ll dis) {
    		for (int i = h[x]; i; i = ne[i]) {
    			int y = to[i]; if (y == fa) continue;
    			dfs(y, x, dis + w[i]), now = 2 * dis;
    			rt[x] = merge(rt[x], rt[y]);
    		}
    		Mx(ans, (Conquer::dis[x] - dis) * 2);
    	}
    	void main(void) {
    		dfs(1, 0, 0), write(ans / 2);
    	}
    }
    
    ll h[N], ne[N<<1], to[N<<1]; ll w[N<<1], tot;
    inline void add(int x, int y, ll z) {
    	ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z;
    }
    
    int Las[N], cnt;
    void dfs(int x, int fa) {
    	for (int i = h[x], y; i; i = ne[i]) {
    		if ((y = to[i]) == fa) continue; dfs(y, x);
    		if (!Las[x]) Conquer::adde(x, y, w[i]), Las[x] = x;
    		else {
    			Conquer::adde(Las[x], ++cnt, 0);
    			Conquer::adde(Las[x] = cnt, y, w[i]);
    		}
    	}
    }
    
    signed main() {
    	int n; read(n), cnt = n;
    	for (int i = 1, x, y, z;i < n; i++)
    		read(x), read(y), read(z), add(x, y, z), add(y, x, z);
    	for (int i = 1, x, y, z;i < n; i++)
    		read(x), read(y), read(z), T2::add(x, y, z), T2::add(y, x, z);
    	dfs(1, 0), Conquer::cnt = cnt, Conquer::n = n, Conquer::main(), T2::main();
    	return 0;
    }
    
  • 相关阅读:
    python命令方式和关键字
    python注释及语句分类
    基于物联网的智能垃圾桶设计
    基于51单片机的交通灯控制设计
    python安装以及版本检测
    python简介
    关于deepin系统安装design compiler的问题解答
    关于安装deepin+window10双系统有时没有声音的问题
    如何使用notepad运行python程序
    15 一个完整的链式队列代码
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13364416.html
Copyright © 2020-2023  润新知