zoukankan      html  css  js  c++  java
  • 树链剖分总结

    树链剖分总结

    原理

    将树边归到至多(logn)条连续树边构成的重边中,再在各条重边上建线段树,每次操作先遍历所有经过的重边再依次线段树上操作,复杂度({logn}^2)

    树剖代码量并不大,只是其包含了线段树;树剖本身并不难,只是看你怎么维护线段树

    实现

    初始化

    两次(dfs)求得所需信息

    第一次求得每个节点重儿子mxs[]、深度等

    int fa[MAXN],dep[MAXN],sz[MAXN],mxs[MAXN];
    void dfs1(int u, int f){
    	fa[u]=f;
    	dep[u]=dep[f]+1;
    	sz[u]=1;
    	int mxsz=-1;
    	for(int i=head[u];i;i=nxt[i]){
    		int v=vv[i];
    		if(v==f) continue;
    		dfs1(v,u);
    		sz[u]+=sz[v];
    		if(sz[v]>mxsz){
    			mxsz=sz[v];
    			mxs[u]=v;
    		}
    	}
    }
    

    第二次划分重边topf[](dfs)idx[]

    int idx[MAXN],topf[MAXN],cnt;
    void dfs2(int u, int top){
    	idx[u]=++cnt;
    	topf[u]=top;
    	if(mxs[u]==0) return;
    	dfs2(mxs[u], top);
    	for(int i=head[u];i;i=nxt[i]){
    		int v=vv[i];
    		if(v==fa[u]||v==mxs[u]) continue;
    		dfs2(v,v);
    	}
    }
    

    查询&修改

    其实都差不多一样,比如下面查询链上最大值的

    int tre_qury(int a, int b){
    	int ans=-INF;
    	while(topf[a]!=topf[b]){
    		if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
    		ans=max(ans, query(1, idx[topf[a]], idx[a]));
    		a=fa[topf[a]];
    	}
    	if(dep[a]<dep[b]) swap(a,b);
    	ans=max(ans, query(1, idx[b], idx[a]));
    	return ans;
    }
    

    如果查询或修改的是子树,那么利用(dfs)序性质即可:

    inline int son_query(int x){
        return query(1, idx[x], idx[x]+sz[x]-1);
    }
    
  • 相关阅读:
    Eclipse工作间的基本配置。
    多态的 好处和弊端。
    线程转换状态。
    成员内部类如何访问。
    实现runnable接口启动线程相比继承Thread类启动线程的优点。
    Java中的命名规范。
    内部类的访问特点。
    那天无意间又看到一篇关于心流的文章
    科技爱好者周刊139
    形势与政策 期末考试
  • 原文地址:https://www.cnblogs.com/santiego/p/11238602.html
Copyright © 2011-2022 走看看