Matching "problem solution" "CF468D" tree

In addition to this blog code from skylee chiefs.

Subject to the effect

A \ (n (n \ le10 ^ 5) \) numbered as \ (1 \ sim n \) tree right band edge points, find a permutation \ ({P_. 1 \} n-SIM \) , so that \ (\ sum dis (i, p_i) \) maximum. Seek to maximize the \ (\ sum dis (i, p_i) \) minimum and lexicographically \ (P \) .

Thinking

Consider the first question. With (\ dis (x)) \ represents the point \ (X \) to the root of the distance. Is not difficult to find \ (\ sum dis (i, p_i) = \ sum (dep_i + dep_ {p_i} -2 \ times dep_ {lca (i, p_i)}) = 2 \ times \ sum dep_i-2 \ times \ LCA dep_ {SUM (I, P_i)} \) . If we can find a suitable point as a root, so that \ (lca (i, p_i) = 1 \) the answer which is the maximum \ (2 \ Times \ SUM dep_i \) . Demonstrated through a point may be found as the root if and only if the point is the center of gravity of the tree, demonstrated as follows (quoted Code Warehouse ):

Set \ (P \) as the focus, if \ (P \) can not be treated as a common point, located \ (T_l \) is \ (P \) size \ (> \ lfloor \ frac n2 \ rfloor \) sub tree whose root is \ (Q \) , then the \ (Q \) pulled out, then, comprises \ (P \) size tree subtree will \ (<n- \ lfloor \ frac n2 \ rfloor = \ lceil \ frac n2 \ rceil \ le \ lfloor \ frac n2 \ rfloor + 1 \ le T_1 \) size, and the \ (Q \) other subtree sizes are clearly smaller than the pulled \ (T_l \) size , so the \ (Q \) size unplug cause the rest of the largest sub-tree than the \ (P \) pulled even smaller, then \ (P \) is not the focus of contradictions. Therefore, the center of gravity can be used as a common point.

Again proved non-focus point can not be treated as a common point, as set \ (P \) as the focus, and \ (Q \) is not the focus, he landed \ (P \) is \ (T_1 \) sub-tree, then there \ (T_1 \) size \ (\ Le \ lfloor \ FRAC n2 \ rfloor \) , and therefore the whole tree deducted \ (T_1 \) size \ (\ GE \ lceil \ FRAC n2 \ rceil \) , can be obtained if \ (Q \) want to be a common point, he must be \ (T_1 \) of the radicals, and \ (T_1 \) is just the right size is \ (\ lfloor \ FRAC n2 \ rfloor \) , and deduct the entire tree \ (T_l \) size to exactly \ (\ lceil \ FRAC N2 \ rceil \) , it can be obtained \ (n-\) is an even number, \ (T_l \) size of \ ( \ FRAC n2 \) , so \ (Q \) is the focus of contradictions.

At this point we have completed the first question can be solved HDU4118 this problem. Now consider the second question, namely, how to obtain the smallest lexicographically \ (the p-\) .

If the arrangement is defined in \ (I \) is the point \ (P_i \) is the point, each point will be split into a tree-point and one exit point, then the subject becomes a match problem.

After removal of the original image into focus \ (T_ {1 \ sim r } \) co \ (R & lt \) subtree, referred subtree \ (T_i \) have \ (in [i] \) th unmatched into point, \ (oUT [I] \) th unmatched points out, obviously the initial state \ (in [I] = oUT [I] = size (T_i) \) . Since each point of the point to be a match for a different sub-tree, the \ (out [i] \ le in [1] + \ ldots + in [i-1] + in [i + 1] + \ ldots + in [R & lt] \) , i.e. \ (in [i] + out [i ] \ Le \ sum_ {J =. 1} ^ R & lt in [J] \) , i.e. \ (in [i] + out [i ] \) is less than the number of non-matching at this time point. If you press \ (1 \ sim n \) of the order of evaluation \ (P_i \) , then for each time point for each sub-tree \ (T_j \) , are \ (in [j] + out [j] \ I +. 1-n-Le \) .

If the subtree presence \ (T_j \) , satisfies \ (in [J] + OUT [J] = n--I +. 1 \) , then \ (P_i \) must be \ (T_j \) are taken as to ensure lexicographically smallest, the \ (T_j \) smallest point as \ (P_i \) can.

If there is a \ (T_j \) , may be from any different than a \ (I \) subtree belongs subtree selected minimum value.

The minimum value can be maintained by the segment tree, red-black trees, binary heap data structure and the like. Consider using std::set(red-black tree), with std::set in[N]maintaining each subtree all unmatched point numbers std::set minto maintain each of the sub-tree is not the lowest numbered match point, std::set> setrecording each subtree not match the total number of points and the point and the sub-tree number.

Time complexity \ (\ mathcal O (n-\ log n-) \) .

Source

#include<cstdio>
#include<set>
#include<utility>
using namespace std;

#define rep(i,__l,__r) for(signed i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
// #define FILEOI
// #define int long long
// #define int unsigned

#ifdef FILEOI
# define MAXBUFFERSIZE 500000
    inline char fgetc(){
        static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
    }
# undef MAXBUFFERSIZE
# define cg (c=fgetc())
#else
# define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
    char c;bool f=0;
    while(cg<'0'||'9'<c)f|=(c=='-');
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    if(f)x=-x;
}
inline int qread(){
    int x=0;char c;bool f=0;
    while(cg<'0'||'9'<c)f|=(c=='-');
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return f?-x:x;
}
// template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
    inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
    if(x<0)return (void)(putchar('-'),fwrit(-x));
    if(x>9)fwrit(x/10);
    putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
    return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}

const int MAXN=1e5;

struct edge{
    int to,nxt,w;
    edge(const int T=0,const int N=0,const int W=0):to(T),nxt(N),w(W){}
}e[(MAXN<<1)+5];
int tail[MAXN+5],ecnt;
inline void add_edge(const int u,const int v,const int w){
    e[++ecnt]=edge(v,tail[u],w);tail[u]=ecnt;
    e[++ecnt]=edge(u,tail[v],w);tail[v]=ecnt;
}

int n,siz[MAXN+5],fa[MAXN+5];
LL dis[MAXN+5],ans1;
int rt,tsize=(1<<30)-1;

inline void dfs(const int u,const int ff){
    siz[u]=1;
    int maxx=0;
    for(int i=tail[u],v;i;i=e[i].nxt)if((v=e[i].to)!=ff){
        dfs(v,u);
        siz[u]+=siz[v];
        maxx=Max(maxx,siz[v]);
    }
    maxx=Max(maxx,n-siz[u]);
    if(maxx<tsize)rt=u,tsize=maxx;
}

inline void dfs(const int u){
    ans1+=dis[u];
    for(int i=tail[u],v;i;i=e[i].nxt)if((v=e[i].to)!=fa[u]){
        dis[v]=dis[fa[v]=u]+e[i].w;
        dfs(v);
    }
}

int bel[MAXN+5];
set<int>in[MAXN+5];
//维护每一个子树的入点编号
set<int>minn;
//维护 每个子树合法入点的最小值 的最小值
//每个子树最多只会在 minn 中存在一个节点
set< pair<int,int> >Set;//维护 in[tre]+out[tre] 的最小值以及 tre 的值

inline void init_tre(const int u,const int top){//初始化每一颗子树
    in[bel[u]=top].insert(u);
    // printf("Now u == %d, bel[u] == %d\n",u,bel[u]);
    for(int i=tail[u],v;i;i=e[i].nxt)if((v=e[i].to)!=fa[u])
        init_tre(v,top);
}

inline void link(const int from,const int to){
    int x=bel[from],y=bel[to];
    minn.erase(to);
    //为了处理 rt 的 bel==0 的情况
    if(x){
        Set.erase(mp(siz[x],x));
        Set.insert(mp(--siz[x],x));
    }
    if(y){
        in[y].erase(to);
        if(!in[y].empty())minn.insert(*in[y].begin());
        Set.erase(mp(siz[y],y));
        Set.insert(mp(--siz[y],y));
    }
}

inline int solve(const int ind){
    int ret;
    if(Set.rbegin()->first==n-ind+1 && Set.rbegin()->second!=bel[ind])
        ret=*in[Set.rbegin()->second].begin();
    else
        ret=(bel[ind]!=bel[*minn.begin()] || ind==rt)?(*minn.begin()):(*next(minn.begin()));
        //如果当前点与最小入点不在同一颗子树或者当前点为根, 可直接选取最小入点, 否则要选择下一个
        //为什么直接是下一个即可 ? 因为每一颗子树在 minn 里面的点只会有一个, 可以保证 next 一定不是在同一个子树之内的
    link(ind,ret);
    return ret;
}

signed main(){
#ifdef FILEOI
    freopen("file.in","r",stdin);
    freopen("file.out","w",stdout);
#endif
    for(int i=n=qread(),u,v;i>1;--i){
        qread(u),qread(v);
        add_edge(u,v,qread());
    }
    dfs(1,0);//找到树的重心
    dfs(rt);//根据重心重新建树
    writc(ans1<<1,'\n');
    if(n==1)return puts("1"),0;

    minn.insert(rt);
    // in[rt].insert(rt);
    // bel[rt]=rt;
    // Set.insert(mp(siz[rt]=2,rt));
    //根也算一颗单独的子树
    //此处 Set 里面不能放 rt
    //因为 Set 里面维护的是 rt 的子树, 而 rt 本身并不是子树

    for(int i=tail[rt],v;i;i=e[i].nxt){//预处理每一颗子树
        v=e[i].to;
        init_tre(v,v);
        minn.insert(*in[v].begin());
        Set.insert(mp(siz[v]=(in[v].size()<<1),v));
    }//注意:siz[i] 从此处开始就变为了这个子树中 in+out 的值

    rep(i,1,n)writc(solve(i),' ');
    return 0;
}

Guess you like

Origin www.cnblogs.com/Arextre/p/12222795.html