【CodeChef EDGEST]スパニングツリーのエッジ(+ツリーチェーン分割ヒューリスティックマージ木)

問題の表面を見るにはここをクリック

質問のおおよその意味: 2にあなたを与えるために、\を(N \)木のポイント、各エッジの最初のツリー\(E_1 \) 存在下での第二の木のどのように多くの側面を尋ねる(E_2 \)\このような最初の木は削除することを\(E_1 \)プラス\(E_2 \)を、第二の木が削除\(E_2 \)プラス\(E_1 \)をすべてのスパニングツリーの後に残っています。

問題の意味を転換

ために考慮する\(E_1(X、Y)\) 法的\(E_2(U、V)\)で第二ツリーに必ずしも存在する、\(X \)する(Y \)を\パスを介し。

同様に、\(E_1 \)はまた、最初のツリー内に存在しなければならない\(U \)する(V \)を\パスを介し。

我々は列挙であることを考えると、\(E_1 \) およびそれぞれの側は次のように表すことができる\((X、fa_x)\ ) フォーム。

場合には、ある\(E_1 \)は最初のツリーに存在する\(U \)(V \)\、経路の上方\(U、V \)で存在すべきである(X \)\サブツリー内で\(X \)外側のサブツリー。

そこで問題は、ドットで最初のツリーのそれぞれのために、意図されてしまう\(X \) ツリー内の最初の親ノードがされていれば\(fa_x \) 二木に求めている\ (X \)する\(fa_x \)パスが多くのエッジが存在する\((U、V)\)満足\(U、V \)に存在する\(X \)サブツリー、1つの中\(X \)サブツリーの外。

チェーン+ツリーの分割ヒューリスティックマージツリー

ための第二のツリーを検討ツリーチェーン細分化のための木のツリーヒューリスティックマージを

我々は、各対処\(X \) 第二の断面ラインツリーツリーツリーの場合、最初のツリー\(X \)サブツリーポイント\(1 \)、\ (X \ )サブツリーの外側のポイント\(0 \)

その後、我々は交差して第二の木ツリーの外に摘み取らすることができます\(のx \)父親のパスに最初の木に、その後、どのように多くのペア隣接の計算\(01 \)

あなたは2つの間隔をマージするとき、私たちは、限り、各区間のその左右端の値として答えを記録した後、左右のセクションを比較し、左と右のセクションに同じです。

それは間隔ジャンプ再ときプロセスは別に統計に2点をジャンプアップし、最終的にアップ最初の2点をマージするため、注意が必要ないくつかの詳細は、合併の交換価値の左右端ポイントとなります。注ツリーのカットアウトクロスパス。

コード

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define LL long long
#define RL Reg LL
#define CL Con LL&
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define swap(x,y) (x^=y^=x^=y)
using namespace std;
int n;struct edge {int to,nxt;};
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C==E&&(clear(),0),*C++=c)
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI,C=FO,E=FO+FS;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
        I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class Tree1//题意中的第二棵树,树链剖分
{
    private:
        int ee,d,lnk[N+5],Sz[N+5],son[N+5],fa[N+5],dep[N+5],dfn[N+5],Top[N+5];edge e[N<<1];
        struct Il//区间
        {
            int L,R,S;I Il(CI x=0,CI y=0,CI v=0):L(x),R(y),S(v){}
            I Il operator + (Con Il& o) {return ~S?(~o.S?Il(L,o.R,S+o.S+(R^o.L)):*this):o;}//合并区间
        };
        template<int SZ> class SegmentTree//树剖线段树
        {
            private:
                #define LT l,mid,rt<<1
                #define RT mid+1,r,rt<<1|1
                #define PU(x) (O[x]=O[x<<1]+O[x<<1|1])
                int n;Il O[SZ<<2];
                I void Upt(CI x,CI v,CI l,CI r,CI rt)//单点修改
                {
                    if(l==r) return (void)(O[rt].L=O[rt].R=v);RI mid=l+r>>1;
                    x<=mid?Upt(x,v,LT):Upt(x,v,RT),PU(rt);
                }
                I Il Qry(CI tl,CI tr,CI l,CI r,CI rt)//扣区间
                {
                    if(tl==l&&r==tr) return O[rt];RI mid=l+r>>1;
                    if(tr<=mid) return Qry(tl,tr,LT);if(tl>mid) return Qry(tl,tr,RT);
                    return Qry(tl,mid,LT)+Qry(mid+1,tr,RT);
                }
            public:
                I void Build(CI _n) {n=_n;}I void Upt(CI x,CI v) {Upt(x,v,1,n,1);}
                I Il Qry(CI l,CI r) {return Qry(l,r,1,n,1);}
        };SegmentTree<N> S;
        I void dfs1(CI x)//第一遍树剖dfs
        {
            for(RI i=(Sz[x]=1,son[x]=0,lnk[x]);i;i=e[i].nxt) e[i].to^fa[x]&&
            (
                dep[e[i].to]=dep[fa[e[i].to]=x]+1,dfs1(e[i].to),
                Sz[x]+=Sz[e[i].to],Sz[e[i].to]>Sz[son[x]]&&(son[x]=e[i].to)
            );
        }
        I void dfs2(CI x,CI col)//第二遍树剖dfs
        {
            Top[x]=col,dfn[x]=++d,son[x]&&(dfs2(son[x],col),0);
            for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^fa[x]&&
                e[i].to^son[x]&&(dfs2(e[i].to,e[i].to),0);
        }
    public:
        I void Clear() {memset(lnk,0,sizeof(lnk)),ee=d=0;}I void Add(CI x,CI y) {add(x,y);}
        I void TreeChainDissection() {dfs1(1),dfs2(1,1),S.Build(n);}
        I void Upt(CI x,CI v) {S.Upt(dfn[x],v);}//单点修改
        I int Qry(RI x,RI y)//扣区间
        {
            Il tl,tr;tl.S=tr.S=-1;W(Top[x]^Top[y])
            {
                if(dep[Top[x]]>dep[Top[y]]) tl=S.Qry(dfn[Top[x]],dfn[x])+tl,x=fa[Top[x]];//记录第一个点向上跳的过程
                else tr=S.Qry(dfn[Top[y]],dfn[y])+tr,y=fa[Top[y]];//记录第二个点向上跳的过程
            }
            dfn[x]>dfn[y]?(tl=S.Qry(dfn[y],dfn[x])+tl):(tr=S.Qry(dfn[x],dfn[y])+tr);//判断是哪个点向上跳
            return swap(tl.L,tl.R),(tl+tr).S;//交换第一个点区间左右端值,然后合并
        }
}T1;
class Tree2//题意中的第一棵树,树上启发式合并
{
    private:
        int ee,lnk[N+5],Sz[N+5],son[N+5],ans[N+5];edge e[N<<1];
        I void Fill(CI x,CI lst,CI v)//把整棵子树染成v
        {
            T1.Upt(x,v);for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(Fill(e[i].to,x,v),0);
        }
        I void dfs(CI x,CI lst,CI pos)//遍历
        {
            if(son[x])//如果有子节点
            {
                RI i,p;for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&//处理轻儿子
                    (e[i].to^son[x]?(dfs(e[i].to,x,i+1>>1),Fill(e[i].to,x,0),0):p=i+1>>1);//处理完就染白
                for(dfs(son[x],x,p),i=lnk[x];i;i=e[i].nxt)//处理重儿子
                    e[i].to^lst&&e[i].to^son[x]&&(Fill(e[i].to,x,1),0);//然后把其他儿子重新染黑
            }T1.Upt(x,1),pos&&(ans[pos]=T1.Qry(x,lst));//把当前点染黑,计算答案
        }
    public:
        I void Clear() {memset(lnk,0,sizeof(lnk)),ee=0;}I void Add(CI x,CI y) {add(x,y);}
        I void Init(CI x,CI lst)//初始化求重儿子
        {
            for(RI i=(Sz[x]=1,son[x]=0,lnk[x]);i;i=e[i].nxt) e[i].to^lst&&
                (Init(e[i].to,x),Sz[x]+=Sz[e[i].to],Sz[e[i].to]>Sz[son[x]]&&(son[x]=e[i].to));
        }
        I void DSU_on_Tree()//树上启发式合并
        {
            dfs(1,0,0),Fill(1,0,0);//遍历,清空
            for(RI i=1;i^n;++i) F.write(ans[i]," \n"[i==n-1]);//输出答案
        }
}T2;
int main()
{
    RI Tt,i,x,y;F.read(Tt);W(Tt--)
    {
        T1.Clear(),T2.Clear(),F.read(n);//清空
        for(i=1;i^n;++i) F.read(x,y),T2.Add(x,y),T2.Add(y,x);//读入题意中的第一棵树
        for(i=1;i^n;++i) F.read(x,y),T1.Add(x,y),T1.Add(y,x);//读入题意中的第二棵树
        T1.TreeChainDissection(),T2.Init(1,0),T2.DSU_on_Tree();//求答案
    }return F.clear(),0;
}

おすすめ

転載: www.cnblogs.com/chenxiaoran666/p/CodeChefEDGEST.html