首页 > 其他分享 >[APC001H] Generalized Insertion Sort 题解

[APC001H] Generalized Insertion Sort 题解

时间:2024-12-19 20:31:48浏览次数:3  
标签:Sort APC001H int 题解 位置 结点 确定 阶段 操作

将 \(a_i\) 视为放在结点 \(i\) 上面的球;称位置 \(i\) 对应的球为 \(i\),区别于“位置 \(i\) 上面的球为 \(a_i\)”。

考虑树是一条链的时候怎么做(下称链插入方法):此时只需要将这条链上面的球按照编号从上到下排序。这是一个类似插入排序的过程,维护深度最大的的若干个球编号的相对顺序;每次将根上的球插入正在维护的、相对顺序确定球(下称确定球)当中——只需找到确定球中深度最大且编号比它小的球,并将该球插在这个确定球原本的位置;如果不存在这样的确定球,直接把它放在深度最小的确定球的父亲位置。

如何拓展这个做法?

考虑将整个操作的过程分成若干个阶段,在每个阶段我们将一部分的球还原至其原来的位置并在之后的阶段中忽略它们,且称这些球为操作球。问题在于如何选取每一个阶段的操作球,这里给出一种可能的构造(如果一个球满足如下的条件之一,那么将该球设为操作球):

  • 该球的目标位置是叶子结点;
  • 该球的目标位置有且仅有一个子节点且该子结点对应的球为操作球。

容易得出每个阶段中,操作球构成的子图是若干条互不相交的链。我们实时维护根结点上的球:

  • 如果根结点上的球是操作球,找到其目标位置所在的链,对该球使用链插入方法,并将其标记为确定球,下称操作一
  • 如果根结点上的球是非操作球,找到一个编号最大且没有使用过位置使其上面的球为非确定球(可能是操作球或非操作球),将这个球扔到根结点上,并将该位置标记为使用过,下称操作二
  • 当根结点的球成为确定球或者操作二把所有可能的位置都使用过了,就结束这个阶段(因为如果使用了所有的位置,就表示已经尝试过将所有这样的位置上面的球都“顶”上去了,即处理完了所有的操作球),并把已经确定的结点删了,方便之后的各种操作。

操作二中为什么要选择编号最大的位置?因为根据题目我们知道 \(\forall i, p_i<i\),所以 \(N-1,...,0\) 是原树一种 dfs 序的反序,也就是说这么选只会将原来根结点上的球扔到一条链的底端(或一条有确定球的链上深度最小的确定球上方),感性理解就是如果扔到底只可能把我们想要的操作球往上顶,并且它不会影响下面的球(因为它的下面如果有球,那么只会有确定球)。

进行上述操作时,在所有阶段中操作一最多共做 \(N\) 次(每个球只会归位一次),而操作二在每个阶段中在最差情况下会遍历所有球,所以每个阶段中操作二最多做 \(N\) 次。

上述构造总共会进行多少个阶段?我们只需要考虑一条链使用上述方法(每次去掉若干个不相交子链)最多要几条子链构成。考虑重链剖分,根据经典结论一条链最多被划分为 \(\lceil\log_2N\rceil\) 条链,即最多有 \(\lceil\log_2 2000\rceil=11\) 个阶段,所以总操作次数为 \(N+N\lceil\log_2 N\rceil\le 12N\le 24000\),可以通过此题。

参考代码(GNU C++17):

#include<bits/stdc++.h>
using namespace std;
int main(){
  ios::sync_with_stdio(false);
  int n; cin>>n;
  vector<int> f(n),a(n),t(n),r; f[0]=-1;
  vector<vector<int> > g(n);
  for(int i=1;i<n;i++)
    cin>>f[i],g[f[i]].emplace_back(i);
  for(auto &i:a)cin>>i;
  auto rotate=[&](int u){
    if(int x=a[0];u){
      r.emplace_back(u);
      while(~u)swap(a[u],x),u=f[u];
    }
  }; // 进行一次旋转
  vector<bool> b(n),l(n),w(n);
  while(!b[0]){ // 如果根结点的球没确定就继续构造
    for(int i=n-1;~i;i--)
      if(!b[i]){
        if(g[i].empty())
          l[i]=true,t[i]=i;
        if(g[i].size()==1&&l[g[i][0]])
          l[i]=true,t[i]=t[g[i][0]];
      } // 找到所有操作球
      // 记得要倒着遍历,从下往上找
    int p=n-1;
    while(!w[a[0]]){
      if(l[a[0]]){
        int u=t[a[0]];
        while(w[a[u]]&&a[u]>a[0])u=f[u];
        w[a[0]]=true,rotate(u);
      } // 根结点上是操作球
      else{
        while(~p&&(b[p]||w[a[p]]))p--;
        // 找编号最大且上面有非确定球的位置
        if(~p)rotate(p--);
        else break; // 没有这样的位置
      } // 根结点上是非操作球
    }
    for(int i=0;i<n;i++)
      if(l[i])b[i]=true;
      else{
        vector<int> v;
        for(int j:g[i])
          if(!l[j])v.emplace_back(j);
        g[i]=v;
      } // 一个阶段结束进行删除
  }
  cout<<r.size()<<endl;
  for(int i:r)cout<<i<<'\n';
  return 0;
}

标签:Sort,APC001H,int,题解,位置,结点,确定,阶段,操作
From: https://www.cnblogs.com/physics212303/p/18617881

相关文章

  • [USACO24OPEN] Grass Segments G 题解
    考虑对于一个区间\([l_i,r_i]\),最少重叠长度为\(k_i\),怎样的区间\([l_j,r_j]\)可以与前者产生贡献;首先\(r_j-l_j\gek_i\),在满足这个条件的情况下需要有\(r_j\gel_i+k_i\landl_j\ler_i-k_i\),这里\(\land\)表示合取,即C++中的\(\mathrm{and}\)。正难则反,考虑用长度\(......
  • 题解:P10483 小猫爬山
    思路第一眼我以为是个背包,但由于是分组,所以有多个缆车,明显不能用背包。我做这题是因为老师要求,那是我们在学深搜减枝,所以我就开始写深搜。这一题实际上是先选一直最重的猫,然后搞个\(sum\)数组,每搞一个新缆车的就下一个下标继续放,如果能放就放,当然也要搞一个能放但不放的。减枝......
  • RHCE环境公共问题解决(9.0)
    关于如何使用远程软件进行连接环境问题查看此处网络适配器模式,如果是NAT请修改为仅主机模式Vmware有两张网卡,一张是Vmware1,一张是Vmware8(环境必须用仅主机,避免环境判分错误)默认情况下,仅主机模式修改Vmware1网卡 打开Windows的网络适配器可以看到两张网卡 环境IP为1......
  • AT_agc030_f [AGC030F] Permutation and Minimum 题解
    先去掉相邻两个都填完的位置,对于两个都没填的记个数为\(c\),最后只需要将答案乘上\(c!\)。接下来考虑从小到大枚举所有数进行dp,记\(f_{i,j,k}\)表示考虑完前\(1\simi\),有\(j\)个数需要跟一个位置确定的数匹配,有\(k\)个数需要跟后面一个自由的数匹配,考虑当前的数:如果......
  • AT_agc009_d [AGC009D] Uninity 题解
    一道妙妙题。一句话题意:求点分树的高度最小值。给所有点填上一个数表示它子树\(k\),考虑一种填法什么时候满足条件,发现当且仅当任意两对值相同的点之间的路径上存在一个权值更大的点。考虑随便找一个点作为根从叶子节点开始贪心填值,每次选择能填的最小值,发现这样填最终的值的最......
  • 题解:最优硬币组合问题
    更多算法题的题解见:算法刷题题解汇总(持续更新中)一、问题背景小C有多种不同面值的硬币,每种硬币的数量是无限的。他希望知道,如何使用最少数量的硬币,凑出给定的总金额N。小C对硬币的组合方式很感兴趣,但他更希望在满足总金额的同时,使用的硬币数量尽可能少。例如:小C有三种硬币......
  • 题解:P11409 西湖有雅座
    题解:P11409西湖有雅座题目转送带简洁思路由于数据比较小,可以先预处理出任何两个零件是否能出现在同一栋大楼上。即枚举所有的两个零件,根据题意去模拟判断条件是否满足:\[\foralli,j\inU,f\left(i,j\right)\ge\lceil\frac{\min\left(S\left(i\right),S\left(j\righ......
  • sort算法的使用
    sort算法的使用望文生义,sort是STL内置的一个排序算法,其底层是由多个排序算法的配合的使用。需要包含的头文件#include<algorithm>使用sort(参数1,参数2,参数3)参数1:排序的左端点的迭代器或者地址参数2:排序的右端点的迭代器或者地址参数3:控制排序优先级的函数注意:代......
  • 把半年前完全没思路的题解了的感觉真好
    虽然处理了很多次索引思路,不过最后还是过了。第一眼就有解题思路,这种感觉真不错,要的就是这种打怪升级的正反馈。附上解题代码`#@lcapp=leetcode.cnid=2266lang=python3[2266]统计打字方案数@lccode=startfromcollectionsimportCounterfromfunctoolsimportcac......
  • CF1100F题解
    \(CF1100F\),\(Ivan\)\(and\)\(Burgers\)题意:静态序列查询一个区间中选取任意个数的最大异或和,\((n\le10^6)\)\(sol\):考虑离线做,把询问按\(r\)从小到大排序,每次\(r\)右移时把新框进来的数加入线性基中,同时记录线性基每一位在序列中的位置,贪心的考虑显然位置越靠后越优,查......