当前位置: 首页 > news >正文

CF1967D Long Way to be Non-decreasing

前置知识

基环树,二分

思路

  1. 首先可以想到,选择集合次数应该被修改次数最多的点决定,所以题目实际要求是使最大操作次数最小。

  2. 经典二分模型,问题变为在每个点不超过 \(mid\) 的次修改后是否可以变为单调不降的序列。对于这个问题,考虑贪心,每个点都尽量选比前一个数大的最小值。先图论建模,对于每个值域 \(i\)\(i->b_i\) ,我们发现形成一个内向基环树森林(每个点出度为 \(1\) ),然后判定问题,相当于要求每个点在这些树上走,走不超过 \(mid\) 次,能到达的比前一个数大的最小值。

  3. 如果快速解决上面的问题,我们发现 \(a_i\) 单调不增,所以我们可以考虑用一个 指针扫值域 。每次只用快速判断任意两点在基环树上的距离(这是好做的)。我们可以考虑,将环上任意一边 \((u,b_u)\) 切掉,然后看成一颗以 \(u\) 为根的树。对于两点 \((x,y)\),如果在同一颗树且有祖先关系就直接 \(dep[x]-dep[y]\)(处理了环到环,树到树) ,如果要跨过断掉的边(即路径是 \(x->u->b_u->y\) ,其实就是从树到环的路径) 就是 \(dep[x]-dep[u]+1+dep[y]-dep[b_u]\)

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10,inf=1e9+7;
int n,m,a[N],b[N],fa[N],dfn[N],js[N],siz[N],dep[N],del[N],tot;
vector<int> ve[N];
void add(int x,int y){ve[x].push_back(y);} 
int find(int x)
{if(fa[x]==x)return x;else return fa[x]=find(fa[x]);
}
bool merge(int x,int y)
{int f1=find(x),f2=find(y);fa[f1]=f2;//要把父亲留在环上那个节点       if(f1==f2)return 0;return 1;
}
void dfs(int u)
{dfn[u]=++tot;for(int v:ve[u]){dep[v]=dep[u]+1;dfs(v);}js[u]=tot;
}
bool sub(int x,int y)
{return dfn[x]>=dfn[y]&&dfn[x]<=js[y];
} 
int jl(int x,int y)
{int f1=find(x),f2=find(y);if(f1!=f2) return inf;if(sub(x,y))return dep[x]-dep[y];if(sub(b[del[f1]],y))return dep[x]+1+dep[b[del[f1]]]-dep[y];return inf;
}
bool check(int mid)
{int cur=1;for(int i=1;i<=n;i++){while(jl(a[i],cur)>mid&&cur<=m)cur++;if(cur>m)return 0;}return 1;
}
void solve()
{cin>>n>>m;tot=0;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=m;i++)fa[i]=i,ve[i].clear(),del[i]=dep[i]=0;for(int i=1;i<=m;i++){cin>>b[i]; if(merge(i,b[i]))add(b[i],i);//建反向边 else del[find(i)]=i; }for(int i=1;i<=m;i++){if(fa[i]==i)dfs(del[i]);}int l=0,r=m,ans=-1; //注意n,m不要乱用while(l<=r){int mid=(l+r)>>1;if(check(mid))ans=mid,r=mid-1;else l=mid+1; }cout<<ans<<'\n';return ;	
} 
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t;cin>>t;while(t--)solve();return 0;
} 
http://www.gsyq.cn/news/351.html

相关文章:

  • Proximal SFT:用PPO强化学习机制优化SFT,让大模型训练更稳定
  • 解题报告-洛谷P3773 [CTSC2017] 吉夫特
  • 政治笔记
  • Graspnet视觉抓取(一)——环境搭建
  • 3. 堆排序
  • 总结
  • 【Azure Container App】查看当前 Container App Environment 中的 CPU 使用情况的API
  • TTS微软Azure
  • 解决docker: Error response from daemon: Get “https://registry-1.docker.io/v2/“:连接超时问题
  • 27届春招备战一轮复习--第三期(推荐)
  • 三期集训 日记?
  • 需求爆炸?领歌3步科学精简法,让团队重获掌控力!
  • 在服务器后台运行python服务
  • HCIP回顾—2 OSPF工作过程及状态机制
  • 实时通信的头痛-问题不在WebSocket而是你的框架
  • 你的开发服务器在说谎-热重载与热重启的关键区别
  • AT_agc018_b [AGC018B] Sports Festival
  • 11.5 类与数据类型
  • 接口
  • 无重复字符的最长子串的解题分析
  • python基础——数据容器(序列、集合、字典)
  • 11.4 类与对象的绑定方法
  • 提取符号偏移地址
  • nvm管理node
  • LG10641
  • LG11068
  • scp拷贝文件报错
  • 11.1 定义类和对象
  • C++小白修仙记_LeetCode刷题_队列
  • Fastjson 1.2.47 远程代码执行