zoukankan      html  css  js  c++  java
  • 【HDU1512】Monkey King-左偏树+并查集(左偏树入门题)

    测试地址:Monkey King

    题目大意:有N(N≤100000)只猴子,标号为1~N,每只猴子有一个强壮值,一开始他们互相之间都不认识,但猴子避免不了争吵,它们之间会进行M(M≤100000)次争吵,每次争吵都是标号为a和b的两只互不认识的猴子相互争吵,争吵过后,他们就会分别去找他们所认识的最强壮(强壮值最大)的猴子来决斗,决斗过后决斗的两只猴子的强壮值减半(向下取整),但打斗过后两边的猴子就都会互相认识,互相认识的猴子之间就不会再进行争吵了,你的任务就是对于每次争吵,如果不发生争吵(即两方认识)输出-1,否则输出决斗后两方猴子中最强壮猴子的强壮值。

    做法:初观察这一题,维护互相认识的关系可以用并查集O(N)解决,维护最大的强壮值似乎可以用堆来解决,但是两方猴子互相认识之后,两个堆之间需要合并,如果将一个堆中的元素一个一个插入另一个堆中,复杂度是O(N^2)的,不能接受,这时候就要引出可并堆这个数据结构了,而左偏树则是可并堆的一种实现方法,关于左偏树的教程网上很多这里就不讲了。于是这里我们维护很多个大根堆,每次决斗,删除两个堆的根节点,将它们的强壮值减半,然后再合并回原来的堆中,再将两个堆合并,输出根节点的强壮值即可。并查集可以在合并和删除的过程中一并维护。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,fa[100010];
    struct leftisttree
    {
      int lc,rc,key,dis;
    }nd[100010];
    
    int find(int x) //并查集中的查找
    {
      int r=x,i=x,j;
      while(fa[r]!=r) r=fa[r];
      while(i!=r) j=fa[i],fa[i]=r,i=j;
      return r;
    }
    
    int merge(int x,int y) //合并堆并返回合并后堆的根
    {
      if (!x) return y;
      if (!y) return x;
      if (nd[x].key<nd[y].key) swap(x,y);
      nd[x].rc=merge(nd[x].rc,y);
      int l=nd[x].lc,r=nd[x].rc;
      fa[r]=x;
      if (nd[l].dis<nd[r].dis) swap(nd[x].lc,nd[x].rc);
      nd[x].dis=nd[nd[x].rc].dis+1;
      return x;
    }
    
    int del(int x) //删除一个堆的根节点并返回左右子树合并后的根
    {
      int l,r;
      l=nd[x].lc,r=nd[x].rc;
      fa[l]=l,fa[r]=r;
      nd[x].lc=nd[x].rc=nd[x].dis=0;
      return merge(l,r);
    }
    
    void solve(int x,int y) //求解决斗后最大的强壮值
    {
      int l,r;
      nd[x].key/=2;nd[y].key/=2;
      l=del(x),r=del(y);
      l=merge(l,x),r=merge(r,y);
      l=merge(l,r);
      printf("%d
    ",nd[l].key);
    }
    
    int main()
    {
      while(scanf("%d",&n)!=EOF)
      {
        nd[0].lc=nd[0].rc=0;nd[0].dis=-1;
        for(int i=1;i<=n;i++)
        {
          scanf("%d",&nd[i].key);
          nd[i].lc=nd[i].rc=nd[i].dis=0;
          fa[i]=i;
        }
        scanf("%d",&m);
        for(int i=1,a,b;i<=m;i++)
    	{
    	  scanf("%d%d",&a,&b);
    	  if (find(a)==find(b)) {printf("-1
    ");continue;}
    	  solve(find(a),find(b));
    	}
      }
      
      return 0;
    }
    


  • 相关阅读:
    [SSRS] Use Enum values in filter expressions Dynamics 365 Finance and Operation
    Power shell deploy all SSRS report d365 FO
    display method in Dynamics 365 FO
    How To Debug Dynamics 365 Finance and Operation
    Computed columns and virtual fields in data entities Dynamics 365
    Azure DevOps for Power Platform Build Pipeline
    Create readonly entities that expose financial dimensions Dynamics 365
    Dataentity call stack dynamics 365
    Dynamics 365 FO extension
    Use singletenant servertoserver authentication PowerApps
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793804.html
Copyright © 2011-2022 走看看