D. Dogeforces (贪心构造+并查集维护生成树)

传送门

有一个有根树,带点权,最多500个叶节点,满足根到叶子单条链上的点权严格递减 同时告诉了每对叶节点(i,j)的lca的点权,构建一棵符合条件的树。

首先这个题肯定是从叶子节点往上去构建一棵树的过程,
想到可以用并查集来维护,fa[u]就表示u往上走目前到达的点,
我们把(i,j,lca(i,j))三元组按点权升序排序,点权相同则按顶点编号排序。

枚举排好序的三元组,对于(u,v,w),有两种情况。

  • 先求出u v的根节点r1 r2 ,如果小于w 说明u v的lca的点权就是w,n+=1表示新建一个节点,也就是他们lca的节点编号是n+1.
  • 也可能是r1\r2等于w 那么说明r1\r2就是lca
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 2e5 + 10;
const ll mod = 1e9 + 7;
const ll inf = (ll)4e16+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){
    
    while(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
    
    
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
    
    while(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){
    
    x=x*10+ch-'0';ch=getchar();}
    return x*f;
}


int fa[maxn];
struct node 
{
    
    
    int u,v,w;
    bool operator <(const node &f)const
    {
    
    
        if(w != f.w)
            return w<f.w;
        if(u != f.u)
            return u<f.u;
        return v<f.v;
    }
}b[maxn];
int cnt;
int a[maxn];//点权
int n;//1~n叶子节点
vector<pii> ans;
int find(int x)
{
    
    
    if(fa[x] == x) return x;
    fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
    
    
        for(int j=1;j<=n;j++)
        {
    
    
            int d;scanf("%d",&d);
            if(i<j) b[++cnt]=(node){
    
    i,j,d};
            if(i==j) a[i]=d;
        }
        fa[i]=i;
    }
    sort(b+1,b+cnt+1);
    for(int i=1;i<=cnt;i++)//开始构建这棵树
    {
    
    
        int r1=find(b[i].u),r2=find(b[i].v);
        if(r1==r2) continue;
        if(max(a[r1],a[r2])==b[i].w) 
        {
    
    
            if(a[r1]==b[i].w) 
            {
    
    
                fa[r2]=r1;
                ans.push_back({
    
    r2,r1});
            }
            else 
            {
    
    
                fa[r1]=r2;
                ans.push_back({
    
    r1,r2});
            }

        }
        else //小于 
        {
    
    
            fa[++n]=n;
            a[n]=b[i].w;
            fa[r1]=n,fa[r2]=n;
            ans.push_back({
    
    r1,n});
            ans.push_back({
    
    r2,n});
        }
    }
    cout<<n<<'\n';
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    puts("");
    printf("%d\n",find(1));
    for(pii e:ans) printf("%d %d\n",e.first,e.second);//first是孩子节点 second是父节点
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46030630/article/details/121431604