zoukankan      html  css  js  c++  java
  • 动态点分治复习

    动态点分治复习

    算法思路

    大概就是让一个点管辖一堆点,并构成父子关系,以维护一些东西。发现使重心为管辖点最好。点分树有几个性质,树高logn,可以暴力爬树维护。并且注意这里的父子关系可能在原树上离得很远,要注意区分。

    关于写法

    写两棵树的全局变量非常麻烦,可以封装结构体。注意有时候tree1和tree2要相互调用,可以这样写:

    int dis(int,int);
    struct tree1{
        ...
        void add(int u,int v){
            ...
        }
        void modify(int u,int w){
            ... dis(u,fa[now]) ...
        }
    }t1;
    struct tree2{
        ...
        void get_dis(int a,int b){
            ...
        }
        void dfs(int now){
            ... t1.add(fa[now],now); ...
        }
    }t2;
    int dis(int a,int b){
        return t2.get_dis(a,b);
    }
    

    这样调试会方便一点,因为可以在两个结构体里开一样的变量名。

    核心代码

    	inline void getrt(int u,int pre){
    		sz[u]=1,mx[u]=0;//注意每次都要初始化 
    		for(int i=head[u];i;i=edge[i].nex){
    			int v=edge[i].v;
    			if(vis[v]||v==pre) continue;
    			getrt(v,u);sz[u]+=sz[v];
    			mx[u]=max(mx[u],sz[v]);
    		}
    		mx[u]=max(mx[u],sum-sz[u]);
    		if(mx[u]<mx[rt]) rt=u;
    	}
    	inline void work(int u,int pre){
    		vis[u]=1;fa[u]=pre;
    		for(int i=head[u];i;i=edge[i].nex){
    			int v=edge[i].v;
    			if(vis[v]) continue;
    			sum=sz[v];mx[0]=sz[v];rt=0;
    			getrt(v,0);t2.add(u,rt,v);
    			work(rt,u);
    		}
    	}
    

    做题思路

    维护查询的东西,跟点分治差不多。注意树结构不变。修改,考虑对一些管辖点维护的东西的变化,可以发现这些点就是点分树上到根的路径上的点,暴力爬树修改即可。

    举个例子:

    长度为k的链权值之和

    用动态开点线段树每个点维护经过这个点的长度为k的链长之和,把每个点可以接上的长度为k的链有多少个存起来(总状态数(O(nlog n))),每次爬树用线段树区间修改(注意减去重复的部分),复杂度(nlog^2n)。注意树上联通块大小每次至少减半,于是线段树总共的待修改区间是(O(n))的,这部分常数很小(只要你范围写对)。

  • 相关阅读:
    C#生成满足特定要求的密码
    抽象方法(abstract method) 和 虚方法 (virtual method), 重载(overload) 和 重写(override)的区别于联系
    面试问题 ---C#中的委托
    面试问题
    如何用DOS命令,获取一个目录下的文件数目
    vim怎么把一个写的代码文件另存到任意文件夹里?
    WIN7 不用格式化磁盘怎么把FAT32系统改成NTFS系统
    rhel6 中安装使用finger命令
    Redhat enterpise6 安装unix2dos/dos2unix
    阐述Linux操作系统之rpm五种基本操作
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/12791715.html
Copyright © 2011-2022 走看看