2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


题目链接

https://nanti.jisuanke.com/t/42586

Problem

给定一个 n n n 个点的树,以及参数 k k k,树上每个点均有一个权值 v a l i \\mathrm{val}_i vali

询问树上有序对 ( x , y ) (x,y) (x,y) 的数量,满足以下条件:

  • x x x 不等于 y y y
  • x x x 不是 y y y 的祖先
  • y y y 不是 x x x 的祖先
  • x x x y y y 之间的距离不超过 k k k
  • v a l x + v a l y = 2 × v a l l c a ( x , y ) \\mathrm{val}_x+\\mathrm{val}_y=2\\times \\mathrm{val}_{\\mathrm{lca}(x,y)} valx+valy=2×vallca(x,y)

n , k ≤ 1 0 5 n,k\\le 10^5 n,k105 0 ≤ v a l i ≤ n 0\\le \\mathrm{val}_i\\le n 0valin

Solution

树上统计问题,发现问题可以划分成子树的问题,显然考虑树上启发式合并。

树上两点间距离问题考虑分析 l c a ( x , y ) \\mathrm{lca}(x,y) lca(x,y),假设已知 l c a ( x , y ) = z \\mathrm{lca}(x,y)=z lca(x,y)=z,考虑统计以 z z z 的为根的子数中,对答案有贡献的点对 ( x , y ) (x,y) (x,y) 的数量。

我们在树上启发式合并枚举到第 i i i 课子树的时候,统计与前 i − 1 i-1 i1 棵子树之间的贡献即可。

考虑从给定的五个条件出发分析。条件五: v a l x + v a l y = 2 × v a l l c a ( x , y ) = z \\mathrm{val}_x+\\mathrm{val}_y=2\\times \\mathrm{val}_{\\mathrm{lca}(x,y)=z} valx+valy=2×vallca(x,y)=z,显然此时 v a l x \\mathrm{val}_x valx v a l z \\mathrm{val}_{z} valz 都已经确定了,那么我们就可以得到 v a l y = 2 × v a l z − v a l x \\mathrm{val}_y=2\\times \\mathrm{val}_z-\\mathrm{val}_x valy=2×valzvalx

考虑条件四, x x x y y y 之间的距离不超过 k k k。我们已经知道了 d x d_x dx 和他们的 l c a \\mathrm{lca} lca 的深度 d z d_z dz,显然可以得到 d y = k − d x + 2 × d z d_y=k-d_x+2\\times d_z dy=kdx+2×dz

综上所述,问题转化为了,求前 i − 1 i-1 i1 子树中深度不超过 d y d_y dy 且点的权值为 v a l y \\mathrm{val}_y valy 的点的个数。

考虑 v a l ≤ 1 0 5 \\mathrm{val}\\le 10^5 val105,可以直接维护权值,对于每一个权值,建一个平衡树,即建立 n + 1 n+1 n+1 棵平衡树,以深度为下标序列,维护该权值的点在每个深度的点的个数。

考虑 dsu 深度最多 log ⁡ n \\log n logn,开 1 0 5 10^5 105 个平衡树,每个平衡树最多只有 log ⁡ n \\log n logn 个点,我们只需要维护一个大小为 n log ⁡ n = 2 × 1 0 6 n\\log n=2\\times 10^6 nlogn=2×106 的平衡树即可。

时间复杂度 O ( n log ⁡ n log ⁡ n ) O(n\\log n \\log n) O(nlognlogn)

调了一个小时才A,真的蚌埠住了

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7, maxm = 1e7 + 7, INF = 0x3f3f3f3f;

ll ans;
int val[maxn]; 
int root[maxn];
int deep[maxn];

namespace treap
{ 
	struct node{
	    int l, r; 
	    int key; 
	    int val; 
	    int cnt; 
	    int size; 
	}tr[maxm];
	
	int root, idx;
	
	void pushup(int p){
	    tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + tr[p].cnt;
	}
	
	int get_node(int key){
	    tr[ ++ idx].key = key;
	    tr[idx].val = rand(); 
	    tr[idx].cnt = tr[idx].size = 1;
	    return idx;
	}
	 
	void zig(int &p){//右旋
	    int q = tr[p].l;
	    tr[p].l = tr[q].r;tr[q].r = p, p = q;
	    pushup(tr[p].r), pushup(p);
	}
	
	void zag(int &p){//左旋
	    int q = tr[p].r;
	    tr[p].r = tr[q].l;tr[q].l = p, p = q;
	    pushup(tr[p].l), pushup(p);
	}
	 
	void my_insert(int &p, int key){
	    if(!p) p = get_node(key); 
	    else if(tr[p].key == key) tr[p].cnt ++ ;
	    else if(tr[p].key > key){ 
	        my_insert(tr[p].l, key);
	        if(tr[tr[p].l].val > tr[p].val)
				zig(p);
	    }
	    else { 
	        my_insert(tr[p].r, key);
	        if(tr[tr[p].r].val > tr[p].val)	
				zag(p);
	    }
	    pushup(p);
	}
	 
	void my_delet_one(int &p, int key){ 
	    if(!p) return ;
	    if(tr[p].key == key){ 
	        if(tr[p].cnt > 1) tr[p].cnt -- ;
	        else if(tr[p].l || tr[p].r){
	            if(!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val){ 
	                zig(p);
	                my_delet_one(tr[p].r, key);
	            }
	 
	            2019年ICPC南昌网络赛 J. Distance on the tree 树链剖分+主席树

2019年ICPC南昌网络赛 J. Distance on the tree(树链剖分+主席树 查询路径边权第k大)

2019 (CCPC-Final 2019) K. Russian Dolls on the Christmas(dsu one tree)

ICPC2019南昌区域赛

2019 ICPC 南昌网络赛

2019 ICPC 南昌 Winner