CF798E. Mike and code of a permutation

题意:

排列p,编码了一个序列a。对于每个i,找到第一个\(p_j > p_i\)并且未被标记的j,标记这个j并\(a[i]=j\)。给出a求一个可行的p,保证有解。\(n \le 500000\)


官方题解很详细

令\(b(i) = a^{-1}(i)\),也就是说\(b_i\)表示i被谁标记了

容易想到把小于关系用边表示然后拓扑排序

将没有的a和b置为n+1

我们从题目中能直接得到两种小于关系:\((i,b_i)\),以及\(j \in [1,a_i-1], b_j > i, j \neq i\)

第二种关系可以用线段树得到

但我们不能遍历所有边,否则会退化成\(O(n^2)\)

所以使用dfs式的拓扑排序,dfs到一个节点时直接将他从线段树中删除(也就是删除了他的所有入边)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
#define mid ((l+r)>>1)
#define lc x<<1
#define rc x<<1|1
#define lson lc, l, mid
#define rson rc, mid+1, r
#define pii pair<int, int>
#define fir first
#define sec second
const int N = 5e5+5;
inline int read(){
char c=getchar(); int x=0,f=1;
while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
} int n, a[N], b[N], vis[N]; namespace S {
pair<int, int> t[N<<2];
void build(int x, int l, int r) {
if(l == r) t[x] = make_pair(b[l], l);
else {
build(lson);
build(rson);
t[x] = max(t[lc], t[rc]);
}
}
pii que(int x, int l, int r, int ql, int qr) {
if(ql<=l && r<=qr) return t[x];
else {
if(qr <= mid) return que(lson, ql, qr);
if(mid < ql) return que(rson, ql, qr);
return max(que(lson, ql, qr), que(rson, ql, qr));
}
}
void del(int x, int l, int r, int p) {
if(l == r) t[x] = make_pair(0, l);
else {
if(p <= mid) del(lson, p);
else del(rson, p);
t[x] = max(t[lc], t[rc]);
}
}
} int q[N], m, p[N];
void dfs(int u) {
vis[u] = 1;
S::del(1, 1, n, u);
if(b[u] != n+1 && !vis[b[u]]) dfs(b[u]);
if(a[u] > 1) while(true) {
pii v = S::que(1, 1, n, 1, a[u]-1);
if(v.fir > u) dfs(v.sec);
else break;
}
q[++m] = u;
}
int main() {
//freopen("in", "r", stdin);
n = read();
for(int i=1; i<=n; i++) {
a[i] = read();
if(a[i] != -1) b[a[i]] = i;
else a[i] = n+1;
}
for(int i=1; i<=n; i++) if(!b[i]) b[i] = n+1;
S::build(1, 1, n);
for(int i=1; i<=n; i++) if(!vis[i]) dfs(i);
m = 0;
for(int i=1; i<=n; i++) p[q[i]] = ++m;
for(int i=1; i<=n; i++) printf("%d ", p[i]);
}

CF798E. Mike and code of a permutation [拓扑排序 线段树]的更多相关文章

  1. Nowcoder Hash Function ( 拓扑排序 && 线段树优化建图 )

    题目链接 题意 : 给出一个哈希表.其避免冲突的方法是线性探测再散列.现在问你给出的哈希表是否合法.如果合法则输出所有元素插入的顺序.如果有多解则输出字典序最小的那一个.如果不合法则输出 -1 分析 ...

  2. P3588 [POI2015]PUS(拓扑排序+线段树)

    P3588 [POI2015]PUS 对于每个$(l,r,k)$,将$k$个位置向剩下$r-l-k+1$个位置连边,边权为$1$,这样就保证$k$个位置比剩下的大 先给所有位置填$1e9$保证最优 然 ...

  3. Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)

    先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...

  4. hdu 5638 Toposort (拓扑排序+线段树)

    Toposort Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  5. hdu 5195 DZY Loves Topological Sorting (拓扑排序+线段树)

    DZY Loves Topological Sorting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 ...

  6. [Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和)

    [Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和) E. Permuta ...

  7. HDU 4917 Permutation 拓扑排序的计数

    题意: 一个有n个数的排列,给你一些位置上数字的大小关系.求合法的排列有多少种. 思路: 数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图.而且题目保证有解,所以 ...

  8. 【BZOJ-3832】Rally 拓扑序 + 线段树 (神思路题!)

    3832: [Poi2014]Rally Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 168  Solved:  ...

  9. [BZOJ2815][ZJOI2012]灾难(拓扑排序/支配树)

    支配树目前只见到这一个应用,那就不独分一类,直接作为拓扑排序题好了. 每个点向所有食物连边,定义fa[x]为x的支配点,即离x最近的点,满足若fa[x]灭绝,则x也要灭绝. 这样,将fa[x]向x连边 ...

随机推荐

  1. UVA424高精度加法

    One of the first users of BIT's new supercomputer was Chip Diller. He extended his exploration of po ...

  2. JAVA多线程之CountDownLatch

    前序: 上周测试给开发的同事所开发的模块提出了一个bug,并且还是偶现. 经过仔细查看代码,发现是在业务中启用了多线程,2个线程同时跑,但是新启动的2个线程必须保证一个完成之后另一个再继续运行,才能消 ...

  3. 通过案例理解position:relative和position:absolute

    w3school过了HTML的知识之后,觉得要自己单纯地去啃知识点有点枯燥,然后自己也很容易忘记,所以便找具体的网站练手便补上不懂的知识点.position:relative和postion:abso ...

  4. 拿到List<Map<String,String>>对用属性的值。。。。。。。

    list.get(i).get("orderNumber") 来拿到下面的对应属性的值

  5. [国嵌笔记][036][关闭MMU和CACHE]

    关闭MMU和CACHE 1.Cache是一种容量小,但存取速度非常快的存储器,它保存最近用到的存储器中数据的拷贝.按功能分为ICache(指令Cache)和DCache(数据Cache) 2.虚拟地址 ...

  6. 浅析const、let与var

    以前无论声明变量还是常量,总是使用var一勺端,知道接触了es6之后,发现原来变量.常量的声明其实是很讲究的. 这里简单来谈谈var.const与let. 1.var.var声明的变量没有块级作用域, ...

  7. AD转换

    一.AD转换的概念  AD转换的功能是把模拟量电压转换为数字量电压.DA转换的功能正好相反,就是讲数字量转换位模拟量. 二.芯片PCF8591介绍 PCF8591是一个单片集成.单独供电.低功耗.8- ...

  8. vi的常用命令

    https://zhidao.baidu.com/question/332242228.html vi的基本操作 a) 进入vi 在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面: $ v ...

  9. Rootkit 核心技术——利用 nt!_MDL(内存描述符链表)突破 SSDT(系统服务描述符表)的只读访问限制 Part I

    -------------------------------------------------------- 在 rootkit 与恶意软件开发中有一项基本需求,那就是 hook Windows ...

  10. Windbg+VirtualBox双机调试环境配置(XP/Win7/Win10)

    一.下载WDK10 https://developer.microsoft.com/zh-cn/windows/hardware/windows-driver-kit 安装Windows驱动程序工具包 ...