初涉树链剖分 hrbust 2065

来源:互联网 发布:加内特生涯数据排行 编辑:程序博客网 时间:2024/06/18 14:03

一般适用于对于树的区间查询与修改。

几个定义:

树链:树上两点之间的路径。

剖分:将树上的边划分为轻边和重边。

重儿子:在 u 的儿子节点中,siz最大的那个节点即为 u 的重儿子。(若存在多个,则任选一个)

轻儿子:除重儿子之外的所有儿子节点均为轻儿子。

重边:父节点与重儿子之间的连边。

轻边:父节点与轻儿子之间的连边。

重链:由重边首尾相连组成的路径。


操作之前需要通过dfs初始化一些信息,fa[] , son[] , siz[] , top[] , dot_site[] , dep[] ,seg[]。 

fa[s] :s 的父节点。根节点无意义。

son[s] :s的重儿子。叶子节点无意义。

dep[s] :s的深度。

top[s] :s所在链的深度最小的点。

siz[s] :以s为根节点的子树上的节点总数。

dot_site[s] , s 在dfs时的时间戳。

seg为dfs时的次序。



如图所示:

途中粗线即为重边,细线即为轻边。

则图中重链有 :1. (1 -> 4 -> 7 -> 10) 2. (2 -> 12)  3.  ( 6->9 ) 。

图中点旁边的数字即为相应的点的 top[] 。

为了保证重链上的点在 dfs 时连续,则在dfs时要优先对其重儿子进行dfs(显然除叶子节点外的所有节点均存在重儿子)。

则dfs完成后 seg存储的内容为 { 1,4,7,10,11,6,9,5,2,12 , 3}。


然后对 seg 建立线段树,继而对线段树进行查询和更新。

因为任意两点间的重链和轻边的数量均不超过 log(n),n 两点之间的边的条数,所以在对任意一段路径查询和更新时,其对线段

树的操作次数不会超过2*log(n)。(所示树链剖分的一个性质吧)。


以查询为例。

while(1)

{

设 fu = top[u] , fv = top[v]。

1. 当fu != fv(设 dep[fu] > dep[fv] ) 时,查询seg[] 的子区间 [ dot_site[fu] , dot_site[u] ]上的最值  , u = fa[fu] .

2. 当 fu == fv 时,u,v在一条重链上,若 u == v,查询结束,否则查询 [dot_site[ u ] ,dot_site[ v ] ] (设dep[u] < dep[v]),查询结束。

}


心情有点小低谷。。。墨迹了好久才写完。。。离别的前奏总是这样伤感。


___________ Updata 3.28_____________


总算有一份还算满意的代码了。。

#include <iostream>#include <algorithm>#include <cstdlib>#include <cstdio>#include <cstring>#include <queue>#include <cmath>#include <stack>#pragma comment(linker, "/STACK:1024000000");#define EPS (1e-6)#define LL long long#define ULL unsigned long long int#define _LL __int64#define _INF 0x3f3f3f3f#define Mod 1000000007using namespace std;const int MAXN = 30010;struct N{    int u,v,next;}edge[MAXN*2];int head[MAXN];int Top;void Link(int u,int v){    edge[Top].u = u , edge[Top].v = v , edge[Top].next = head[u] , head[u] = Top++;}int Top_E;int siz[MAXN],fa[MAXN],son[MAXN],dot_site[MAXN],dep[MAXN],top[MAXN],val[MAXN],seg[MAXN];void dfs1(int s,int pre,int d){    dep[s] = d , fa[s] = pre , siz[s] = 1 , son[s] = -1;    for(int p = head[s] ; p != -1; p = edge[p].next)    {        if(edge[p].v != pre)        {            dfs1(edge[p].v,s,d+1);            if(son[s] == -1 || siz[son[s]] < siz[edge[p].v])                son[s] = edge[p].v;            siz[s] += siz[edge[p].v] + 1;        }    }}void dfs2(int s,int pre,int T){    top[s] = T , dot_site[s] = ++Top_E , seg[Top_E] = s ;    if(son[s] == -1)        return ;    dfs2(son[s],s,T);    for(int p = head[s] ; p != -1; p = edge[p].next)    {        if(edge[p].v != son[s] && edge[p].v != pre)        {            dfs2(edge[p].v,s,edge[p].v);        }    }}struct ST{    int Max,Sum;}st[MAXN*4];void Init(int site, int l , int r){    if(l == r)    {        st[site].Max = val[seg[l]] , st[site].Sum = val[seg[r]];        return ;    }    int mid = (l+r)>>1;    Init(site<<1,l,mid);    Init(site<<1|1,mid+1,r);    st[site].Sum = st[site<<1].Sum + st[site<<1|1].Sum;    st[site].Max = max(st[site<<1].Max , st[site<<1|1].Max);}void Updata(int site,int l,int r,int x){    if(l == r && r == x)    {        st[site].Max = val[seg[l]] , st[site].Sum = val[seg[r]];        return ;    }    int mid = (l+r)>>1;    if(x <= mid)        Updata(site<<1,l,mid,x);    else        Updata(site<<1|1,mid+1,r,x);    st[site].Sum = st[site<<1].Sum + st[site<<1|1].Sum;    st[site].Max = max(st[site<<1].Max , st[site<<1|1].Max);}ST Query(int site,int L,int R,int l,int r){    if(L == l && R == r)    {        return st[site];    }    int mid = (L+R)>>1;    if(r <= mid)        return Query(site<<1,L,mid,l,r);    else if(mid < l)        return Query(site<<1|1,mid+1,R,l,r);    ST t1,t2,t3;    t1 = Query(site<<1,L,mid,l,mid);    t2 = Query(site<<1|1,mid+1,R,mid+1,r);    t3.Max = max(t1.Max,t2.Max);    t3.Sum = t1.Sum + t2.Sum;    return t3;}int main(){    //freopen("C.in","r",stdin);    //freopen("C.out","w",stdout);    char s[20];    int n,i;    int u,v;    while(scanf("%d",&n) != EOF)    {        memset(head,-1,sizeof(int)*(n+2));        Top = 0;        for( i= 1;i < n; ++i)        {            scanf("%d %d",&u,&v);            Link(u,v);            Link(v,u);        }        for(i = 1;i <= n; ++i)        {            scanf("%d",&val[i]);        }        dfs1(1,-1,1);        Top_E = 0;        dfs2(1,-1,1);        Init(1,1,Top_E);        int q;        scanf("%d",&q);        while(q--)        {            scanf("%*c%s %d %d",s,&u,&v);            if(s[1] == 'H')            {                val[u] = v;                Updata(1,1,Top_E,dot_site[u]);            }            else            {                ST anw,temp;                anw.Sum = 0;                anw.Max = val[u];                int fu = top[u],fv = top[v];                while(fu != fv)                {                    if(dep[fu] < dep[fv])                        swap(u,v),swap(fu,fv);                    temp = Query(1,1,Top_E,dot_site[fu],dot_site[u]);                    anw.Sum += temp.Sum;                    anw.Max = max(anw.Max,temp.Max);                    u = fa[fu];                    fu = top[u];                }                if(dep[u] < dep[v])                    swap(u,v);                temp = Query(1,1,Top_E,dot_site[v],dot_site[u]);                anw.Sum += temp.Sum;                anw.Max = max(anw.Max,temp.Max);                if(s[1] == 'M')                    printf("%d\n",anw.Max);                else if(s[1] == 'S')                    printf("%d\n",anw.Sum);            }        }    }    return 0;}




0 0
原创粉丝点击