P9150 邮箱题

Alex_Wei 做法妙。

思路

首先我们可以建出两张图,一张是按照题目的要求形成的有向图,一张是由有向边 \((i,k_i)\) 形成的钥匙图。

在钥匙图中,每个点有且仅有一入度一出度,其形成了若干个环。

考虑当前点 \(i\),模拟题目过程不断跳点,跳出的序列为 \(a=\{i,k_i,k_{k_i},\dots,j \}\)。对于 \(k_j\) 的可到达性我们进行探究。

  1. \(k_j \neq i\)。
  2. 其次存在一个 \(p\) 使得原图中存在边 \((p\to k_j)\),且 \(j\) 可到达 \(p\)。

如何判定条件 2 呢?由于 \(a_i\) 可到达 \(a_{i+1}\),每次序列拓展 \(a_p=j\) 时,考虑 \(p\) 的返租边 \(a_p\to a_q(q<p)\),则 \(a_q\) 到 \(a_p\) 之间强连通,使用并查集维护强连通块,加入 \(k_j\) 时枚举边 \(u\to k_j\) 找是否有 \(u\in a\) 且 \(u\) 与 \(j\) 强连通。

复杂度 \(O(nm\alpha)\)。

这么跑肯定会炸,发现处理环的过程中会经过大量重复的点,能否利用已经求出的点的贡献呢?

将环复制两倍,破环为链,链上前一个点的答案就是该点的答案,如果答案统计时超过了环的长度,那么答案就为环长。

设现在的链为 \(c\),如果 \(c_{i+1}\sim c_L\) 的答案已经求出,那么钥匙图上会形成若干条链,表示链头开始可以走到链尾;原图上是若干个子图,这些子图间可能有边相连,但由于根据题目条件这两个子图互不可达,这里仍然认为是两个子图;也就是一个子图对应一条钥匙图上的链。

对子图中的强连通分量进行缩点,发现最终缩成了一条链。

下文不加特殊说明,均有以下几点约定:

  1. 链均指子图缩点形成的链。

  2. \(c_u\to c_v\) 表示用 \(c_u\sim c_v\) 中的点形成的子图缩点后形成的链。

  3. 单个 \(c_u\) 仍表示一个破环为链后 \(c\) 序列的一个点。

  4. \(c_i\) 视为新加入的点。

  5. 点 \(c_u\) 的编号为 \(u\)。

新加入点 \(c_i\) 就相当于判断 \(c_i\to c_i\) 能否和 \(c_{i+1}\to c_p\) 合并,合并之后再次判断 \(c_i\to c_p\) 能否和 \(c_{p+1}\to c_{p`}\) 合并,不断重复链合并,直到无法进行下一次合并。

对于链 \(c_i \to c_p\) 和 \(c_{p+1}\to c_{p`}\),根据朴素做法的判断条件,找到 \(c_u\) 与 \(c_p\) 强连通且存在边 \(c_u\to c_{p+1}\)(这里是原图中的有向边),就可以合并链。

\(c_u\) 换一个角度找会更方便,找存在边 \(c_u\to c_{p+1}(u\in[i,p])\) 的最大的 \(u\),判断 \(c_u,c_p\) 是否共一个强连通分量,因为显然如果存在 \(v<u\) 且 \(c_v,c_p\) 属于同一个强连通分量,\(c_u,c_p\) 也属于同一个强连通分量。

合并链之后,作为一条新的链首先要进行缩点,我们不可能枚举第二条链上所有的返祖边(即满足 \(i<j\) 且村子于原图的边 \(c_j\to c_i\))。一个好的想法是,对于 \(c_i \to c_p\),维护所有终点编号不小于 \(i\) 且未考虑过的返祖边,合并时直接暴力跑第二条链上返祖边的影响然后合并即可。

这样就结束了吗?

仔细思考合并的过程,如果 \(c_i \to c_p\) 能和 \(c_{p+1}\to c_{p`}\) 合并,一定是由于 \(c_i\) 带来的新变化使得这两条链可以合并,否则这两条链在 \(c_i\) 加入之前就合并为一条链了。

影响链合并的因素只有 \(c_u\),所以说 \(c_i\) 的加入带来了新的可以选择的 \(c_u\),而 \(c_u\) 与 \(c_p\) 共一个强连通分量,可以证明 \(c_i\) 与 \(c_p\) 共一个强连通分量。

这样子对于每一条链,维护编号最大还有未贡献的返祖边的节点 \(c_x\),这些返祖边的终点 \(u\) 满足 \(u\in c\) 且 \(i\leq k(c_k=u)\),最后把新链头 \(c_i\sim c_x\) 合并为同一个点即可。

实现时建出反边,每次用 \(c_i\) 更新后面的链即可。

CODE

#include<bits/stdc++.h>
using namespace std; const int maxn=3e6+5; struct dsu
{
int f[maxn];
inline int fr(int u){return f[u]==u?u:f[u]=fr(f[u]);}
inline void merge(int x,int y){f[fr(y)]=fr(x);}
}ch,cy; int n,m;
int k[maxn],val[maxn],pre[maxn],ans1[maxn],ans2[maxn],in[maxn],cyc[maxn]; vector<int>E[maxn]; bool vis[maxn]; inline void solve()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&k[i]);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
E[y].push_back(x);
}
for(int i=1;i<=n;i++)
{
if(vis[i]) continue;
int p=i,ct=0;
while(!in[p]) cyc[++ct]=p,in[p]=ct,p=k[p];
for(int j=ct*2;j;j--)
{
ch.f[j]=cy.f[j]=j;val[j]=pre[j]=0;
int id=cyc[j>ct?j-ct:j];
for(int it:E[id])
{
if(!in[it]) continue;
it=in[it];
if(it+ct<j) it+=ct;
if(it>j) it-=ct;
pre[j]=max(pre[j],it);
if(it<j) it+=ct;
if(it<=ct*2) val[ch.fr(it)]=max(val[ch.fr(it)],cy.fr(it));
}
while(1)
{
while(1)
{
int cyid=cy.fr(j),chid=ch.fr(j);
if(cyid<val[chid]) cy.merge(cyid+1,cyid);
else break;
}
int cyid=cy.fr(j),chid=ch.fr(j);
val[chid]=0;
if(chid==ct*2||cyid!=chid||pre[chid+1]<j) break;
ch.merge(chid+1,chid);
}
ans1[id]=min(ct,ch.fr(j)-j+1);
ans2[id]=min(ct,cy.fr(j)-j+1);
}
for(int j=1;j<=ct;j++) in[cyc[j]]=0,vis[cyc[j]]=1;
}
for(int i=1;i<=n;i++) printf("%d %d\n",ans1[i],ans2[i]);
for(int i=1;i<=n;i++) vis[i]=false,E[i].clear();
} int main()
{
int _;
scanf("%d",&_);
while(_--) solve();
}

P9150 邮箱题的更多相关文章

  1. 【leetcode 简单】 第五十三题 删除重复的电子邮箱

    编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个. +----+------------------+ | Id | Email | +-- ...

  2. 笔试测试开发题三道(python)

    笔试遇到的三道测试开发题,虽然都不难,但关键还是思路吧!我想在开发东西的时候应该具备的就是思路,有了思路尝试去写,或查相关文档或代码,在此基础上需要不断调整最终达到需求.思路又是在不断练习中获得的. ...

  3. Java基础算法集50题

    最近因为要准备实习,还有一个蓝桥杯的编程比赛,所以准备加强一下算法这块,然后百度了一下java基础算法,看到的都是那50套题,那就花了差不多三个晚自习的时间吧,大体看了一遍,做了其中的27道题,有一些 ...

  4. CodeForces 589A Email Aliases (匹配,水题)

    题意:给定于所有的邮箱,都是由login@domain这样的形式构成,而且字符都是不区分大小写的. 我们有一种特殊类型的邮箱——@bmail.com, 这种邮箱除了不区分大小写外—— 1,'@'之前的 ...

  5. CTF---Web入门第十四题 忘记密码了

    忘记密码了分值:20 来源: Justatest 难度:中 参与人数:7706人 Get Flag:2232人 答题人数:2386人 解题通过率:94% 找回密码 格式:SimCTF{ } 解题链接: ...

  6. ProjectEuler 做题记录

    退役选手打发时间的PE计划 挂在这里主要是dalao们看到有什么想交流的东西可以私聊哦(站内信或邮箱吧)~~当然现在高三也不怎么能上网. 2017/8/11  595 :第一题QAQ 2017/8/1 ...

  7. OCP 认证考试报名费技巧题库051052053解析合格线

    本人于2017年4月22日通过参加OCP考试,第一次参加,一天之内考了三门,三门一次性通过,052 - 95% ,053 - 86% ,051 - 100% 一.关于考试考试报名费: 052:158$ ...

  8. 我的第二个独立开发的邮箱类App—“简邮”(支持QQ、雅虎、阿里云、Outlook)

    360手机市场地址: 360市场 其它市场还在审核,囧... 为什么做这个App? 主要有两个原因 1.10月份正逢校招季,--当时和面试官介绍了这个APP 2.在苹果手机上看到一款内置的邮箱app支 ...

  9. leetcode算法题整理

    一.线性表,如数组,单链表,双向链表 线性表.数组 U1.有序数组去重,返回新数组长度 A = [1,1,2] -> [1,2] 返回2   分析:其实一般数组的问题都可以用两个指针解决,一个指 ...

  10. ProjectEuler && Rosecode && Mathmash做题记录

    退役选手打发时间的PE计划 挂在这里主要是dalao们看到有什么想交流的东西可以私聊哦(站内信或邮箱吧) 2017/8/11  PE595 :第一题QAQ 2017/8/12  PE598 2017/ ...

随机推荐

  1. pyinstall通过配置.spec文件引用资源文件

    pyinstall通过配置.spec文件引用资源文件 pyinstall可以自动将所有依赖的.py文件连接起来编译成一个可执行exe文件,但是如果在程序中 使用了外部资源,如图片,或者是其它的配置文件 ...

  2. C++ 项目目录结构

    目录结构 project_root/ ├── bin/ # 可执行文件目录 │ ├── my_app # 可执行文件 │ └── ... # 其他可执行文件或脚本 │ ├── build/ # 编译产 ...

  3. Mac 使用 Caps Lock 键切换输入法失灵问题解决

    Mac 上的 Caps Lock 键对于多语言用户来说,除了切换输入大小写的作用外还承担着切换输入法的功能.正常情况下,轻按一下 Caps Lock 键是切换输入法,长按是切换输入大小写.然而有时这个 ...

  4. DigitalOcean Control (doctl) 使用方法

    安装 macOS brew install doctl Ubuntu sudo snap install doctl # 授予 snap 应用额外权限 sudo snap connect doctl: ...

  5. Vuex的四个轻骑兵:mapState、mapGetter、mapMutation、mapAction(转载)

    vuex进阶一.state1.1 引入vuex 以后,我们需要在state中定义变量,类似于vue中的data,通过state来存放状态 import Vue from 'vue'import Vue ...

  6. Java多线程并发之同步容器和并发容器-第一篇

    Java多线程并发之同步容器和并发容器-第一篇 概述 本文主要讲解在Java多线程并发开发中,集合中有哪些支持并发的的.什么是同步容器(集合),什么是并发容器(集合)?并发容器分类有哪些?每个分类都有 ...

  7. Angular 18+ 高级教程 – Component 组件 の @let Template Local Variables

    前言 Angular 在 v18.1 推出了 Template 新语法 @let. 这个 @let 和上一篇教的 Control Flow @if, @for, @swtich, @defer 语法上 ...

  8. 【linux】【docker】Docker默认网段配置导致无法访问

    背景 集团有N个基地,所有基地的网络使用的是172.x.x.x网段,这本身没有什么问题!但Docker默认的桥接网段也是172.17.x.x的,如果不修改docker的默认配置会导致个别基地无法访问! ...

  9. cf2009 Codeforces Round 971 (Div. 4)

    A. Minimize! 签到题.计算\((c-a)+(b-c)\)的最小值,其实值固定的,等于\(b-a\). int a, b; void solve() { cin >> a > ...

  10. Diffusion系列-预备知识I -(一)

    预备知识 范数 范数是一种函数,用来度量向量的大小1.在机器学习.信号处理等领域中,范数常常被用作正则化方法,通过对参数向量的范数进行约束,达到控制模型复杂度.防止过拟合等目的.常见的范数有0范数.1 ...