CF 468D

Description


 
 

Input

Output

 

Sample Input

输入1:
2
1 2 3
输入2:
5
1 2 2
1 3 3
2 4 4
2 5 5

Sample Output

输出1:
6
2 1
输出2:
32
2 1 4 5 3
 

Data Constraint

 
首先Ans=dep[i]+dep[p[i]]-2*dep[lca(i,p[i])];
易证当根为重心时Ans取最小值,我们只需要求字典序最小。
接下来就是一个二分图匹配的问题,首先我们贪心的选择。但在某些时候我们不能这样选,当一棵子树未匹配数过多时(即到以后只能自己匹配自己时)我们要优先匹配该树中的点。
那么什么时候是过多呢╮(╯▽╰)╭
我们设L[i]为i子树左边未匹配的点数,R[i]为右边未匹配的点数。
那么当L[i]>Rsum-R[i]时会出现过多的情况,
两边同时加上R[i]变为L[i]+R[i]>Rsum
我们只需用一棵线段树记录L[i]+R[i]看是否出现以上情况即可
 
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;

priority_queue<int> H[100011];

struct Tree{
    int mn,mx,id;
}tr[600011];

Tree emp;
int bel[100011],g[100011],next[200022],y[200022],que[100011],len[200011];
ll dis[100011];
int mx[100011],size[100011],fa[100011],ans[100011],sz[100011];
ll Ans;
int n,i,x,z,q,root,tot,tt;

void star(int i,int j,int k)
{
    tt++;
    next[tt]=g[i];
    g[i]=tt;
    y[tt]=j;
    len[tt]=k;
}

void Bfs(int st)
{
    int l,r,x,j,k;
    memset(size,0,sizeof(size));
    memset(dis,0,sizeof(dis));
    memset(fa,0,sizeof(fa));
    l=r=1;
    que[l]=st;
    while(l<=r){
        x=que[l];
        j=g[x];
        while(j!=0){
            k=y[j];
            if(k!=fa[x]){
                fa[k]=x;
                r++;
                que[r]=k;
                dis[k]=dis[x]+len[j];
            }
            j=next[j];
        }
        l++;
    }
    for(i=n;i>=1;i--){
        x=que[i];
        size[x]++;
        mx[x]=max(mx[x],n-size[x]);
        if(mx[x]<=n/2)root=x;
        size[fa[x]]+=size[x];
        mx[fa[x]]=max(mx[fa[x]],size[x]);
    }
}

void dfs(int x)
{
    int j,k;
    bel[x]=tot;
    sz[tot]++;
    H[tot].push(-x);
    j=g[x];
    while(j!=0){
        k=y[j];
        if(k!=fa[x])dfs(k);
        j=next[j];
    }
}

void Prepare()
{
    int j,k;
    bel[root]=1;
    H[1].push(-root);
    tot=1;
    sz[1]=1;
    j=g[root];
    while(j!=0){
        k=y[j];
        tot++;
        dfs(k);
        j=next[j];
    }
}

Tree Merge(Tree a,Tree b)
{
    Tree c;
    c.mn=min(a.mn,b.mn);
    if(a.mx>b.mx){
        c.mx=a.mx;
        c.id=a.id;
    }
    else{
        c.mx=b.mx;
        c.id=b.id;
    }
    return c;
}

void build(int l,int r,int t)
{
    if(l==r){
        tr[t].mn=-H[l].top();
        if(l!=1)tr[t].mx=sz[l]*2;
        else tr[t].mx=0;
        tr[t].id=l;
        return;
    }
    int mid;
    mid=(l+r)/2;
    build(l,mid,t+t);
    build(mid+1,r,t+t+1);
    tr[t]=Merge(tr[t+t],tr[t+t+1]);
}

void insert(int t,int l,int r,int x,int y,int z)
{
    if(l==r){
        if(z==0)tr[t].mx+=y;
        else tr[t].mn=y;
        return;
    }
    int mid;
    mid=(l+r)/2;
    if(x<=mid)insert(t+t,l,mid,x,y,z);
    if(x>mid)insert(t+t+1,mid+1,r,x,y,z);
    tr[t]=Merge(tr[t+t],tr[t+t+1]);
}

Tree ask(int t,int l,int r,int x,int y)
{
    if(x>y)return emp;
    if(l==x&&r==y)return tr[t];
    int mid;
    mid=(l+r)/2;
    if(y<=mid)return ask(t+t,l,mid,x,y);
    if(x>mid)return ask(t+t+1,mid+1,r,x,y);
    if(x<=mid&&y>mid)return Merge(ask(t+t,l,mid,x,mid),ask(t+t+1,mid+1,r,mid+1,y));
}

void Work()
{
    int i,mi,mn,sum;
    Tree Tl,Tr;
    for(i=1;i<=n;i++)Ans+=dis[i];
    Ans*=2;
    printf("%I64d
",Ans);
    build(1,tot,1);
    sum=n;
    emp.mn=2147483646;
    for(i=1;i<=n;i++){
        if(bel[i]!=1){
            Tl=ask(1,1,tot,1,bel[i]-1);
            Tr=ask(1,1,tot,bel[i]+1,tot);
            mn=min(Tl.mn,Tr.mn);
        }
        else mn=tr[1].mn;
        insert(1,1,tot,bel[i],-1,0);
        insert(1,1,tot,bel[mn],-1,0);
        if(tr[1].mx>sum-1){
            mi=tr[1].id;
            insert(1,1,tot,bel[mn],1,0);
            insert(1,1,tot,mi,-1,0);
            ans[i]=-H[mi].top();
            H[mi].pop();
            if(!H[mi].empty())insert(1,1,tot,mi,-H[mi].top(),1);
            else insert(1,1,tot,mi,2147483646,1);
        }
        else{
            ans[i]=mn;
            H[bel[mn]].pop();
            if(!H[bel[mn]].empty())insert(1,1,tot,bel[mn],-H[bel[mn]].top(),1);
            else insert(1,1,tot,bel[mn],2147483646,1);
        }
        sum--;
    }
    for(i=1;i<n;i++)printf("%d ",ans[i]);
    printf("%d
",ans[n]);
}

int main()
{
    scanf("%d",&n);
    for(i=1;i<n;i++){
        scanf("%d%d%d",&x,&z,&q);
        star(x,z,q);
        star(z,x,q);
    }
    Bfs(1);
    Bfs(root);
    Prepare();
    Work();
}
原文地址:https://www.cnblogs.com/applejxt/p/4476177.html