[JLOI2014]松鼠的新家

来源:互联网 发布:威少刷数据视频 编辑:程序博客网 时间:2024/04/27 06:03

裸的 树链剖分 ^.^
然而 并不用线段树
求x,y的LCA 后 ,在 x上标记加一,y上标记加一 ,lca标记减一,fa[lca]标记减一

#include<stdio.h>int n;int shunxv[300005];int to[600005],next[600005],head[600005],cnt;void add(int x,int y){to[++cnt]=y;next[cnt]=head[x];head[x]=cnt;}int siz[300005],dep[300005],fa[300005],son[300005],top[300005];int candy[300005],ans[300005];void dfs1(int x,int from)//求siz,dep,fa,son {    siz[x]=1;    fa[x]=from;    dep[x]=dep[from]+1;    int maxson=0,posson=0;    for(int i=head[x];i;i=next[i])    {        if(to[i]!=from)        {            dfs1(to[i],x);            siz[x]+=siz[to[i]];            if(maxson<siz[to[i]])            {                maxson=siz[to[i]];                posson=to[i];            }        }    }    son[x]=posson;}void dfs2(int x,int from)//求 top {    top[x]=x;    if(son[from]==x) top[x]=top[from];    for(int i=head[x];i;i=next[i])    {        if(to[i]!=from)        {            dfs2(to[i],x);        }    }}int lca(int x,int y){    if(x==y)    {        return x;    }    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];        else if(dep[top[x]]<dep[top[y]]) y=fa[top[y]];        else {x=fa[top[x]];y=fa[top[y]];}    }    if(dep[x]<dep[y]) return x;    else return y;}void getans(int x,int from){    ans[x]=candy[x];    for(int i=head[x];i;i=next[i])    {        if(to[i]!=from)        {            getans(to[i],x);            ans[x]+=ans[to[i]];        }    }}int main(){    scanf("%d",&n);    int i,j;    for(i=1;i<=n;i++)    {        scanf("%d",&shunxv[i]);    }    for(i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        add(x,y);        add(y,x);    }    int root=shunxv[1];    dfs1(root,0);    dfs2(root,0);    /*for(i=1;i<=n;i++)    {        printf("%d   siz:%d   dep:%d   fa:%d   son:%d   top:%d\n",i,siz[i],dep[i],fa[i],son[i],top[i]);    }*/    /*for(i=1;i<=n;i++)    {        for(j=1;j<=n;j++)        {            printf("%d & %d :  %d\n",i,j,lca(i,j));        }    }*/    for(i=1;i<n;i++)    {        int lcanc=lca(shunxv[i],shunxv[i+1]);        candy[shunxv[i]]++;        candy[shunxv[i+1]]++;        candy[lcanc]--;        candy[fa[lcanc]]--;    }    getans(root,0);    for(i=2;i<=n;i++)    {        ans[shunxv[i]]--;    }    for(i=1;i<=n;i++)    {        printf("%d\n",ans[i]);    }    return 0;}/*99 8 7 6 5 4 3 2 11 23 14 15 22 67 29 63 8*//*http://blog.sina.com.cn/s/blog_7a1746820100wp67.html/*记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1),top[v]表示v所在的链的顶端节点,fa[v]表示v的父亲,son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子),w[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置。只要把这些东西求出来,就能用logn的时间完成原问题中的操作。*/
0 0