zoukankan      html  css  js  c++  java
  • 点分治总结

    概念

    点分治是处理树上路径的一个好方法。(如树上距离、树上路径边数等)

    点分治通过不断找树的重心,划分成若干个子树,在子树内再找重心继续递归。每个子树内分别求解答案。

    复杂度为(O(NlogN))(还取决于(calc)函数的复杂度,(calc)函数的复杂度最大为(O(SZlogSZ))

    代码分析

    注:以P4178 Tree为例(求出树上两点距离小于等于(k)的有序点对数量)

    void ask_rt(int x, int fa) // 找到子树的重心
    {
    	sz[x] = 1;
    	int mx = 0;
    	for (int i = hd[x]; i; i = nxt[i])
    	{
    		int y = to[i];
    		if (vis[y] || y == fa) continue;
    		ask_rt(y, x);
    		sz[x] += sz[y];
    		mx = max(mx, sz[y]);
    	}
    	mx = max(mx, sum - sz[x]);
    	if (mx < mn)
    	{
    		mn = mx;
    		rt = x;
    	}
    	return;
    }
    
    void work(int x, int fa, int s) // 算出以当前子树重心为根x和子树内其他节点y之间的所有距离
    {
    	sta[ ++ top] = s;
    	for (int i = hd[x]; i; i = nxt[i])
    	{
    		int y = to[i], z = w[i];
    		if (vis[y] || y == fa) continue;
    		work(y, x, s + z);
    	}
    	return;
    }
    
    int calc(int rt_, int s) // 找到当前子树内的答案
    {
    	top = 0;
    	work(rt_, 0, s);
    	sort(sta + 1, sta + top + 1);
    	int cnt = 0;
    	for (int i = 1; i < top; i ++ )
    	{
    		int pos = upper_bound(sta + i + 1, sta + top + 1, k - sta[i]) - sta;
    		cnt += (pos - i - 1);
    	}
    	return cnt;
    }
    
    void part(int x) // 进行点分治
    {
    	vis[x] = 1;
    	res += calc(x, 0);
    	for (int i = hd[x]; i; i = nxt[i])
    	{
    		int y = to[i], z = w[i];
    		if (vis[y]) continue;
    		res -= calc(y, z); // 去重,防止重复计算。因为路径会在calc(x,0)和calc(y,0)中都计算一次
    		mn = 1e9, rt = 0, sum = sz[y];
    		ask_rt(y, 0), part(rt);
    	}
    	return;
    }
    
  • 相关阅读:
    Django重要组件(Auth模块)
    Django框架深入了解(总结整理)
    ORM(数据库对象关系映射)代码重写
    Django框架深入了解——DRF之序列化、反序列化
    让无线更自由 TOTOLINK EX750无线中继评测
    matlab常用知识
    点云数据
    运动恢复结构
    Ubuntu下简单的QT绘图程序
    英语词语解释
  • 原文地址:https://www.cnblogs.com/andysj/p/14357846.html
Copyright © 2011-2022 走看看