• CF798E. Mike and code of a permutation [拓扑排序 线段树]


    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 eq 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]);
    }
    
    
  • 相关阅读:
    boost::asio中的implementation_type介绍
    boost::asio::io_service::run学习笔记
    vim使用笔记
    进程、线程运行状态查看包括线程在cpu上运行情况
    c++自旋锁——学习笔记
    grep搜索过滤指定目录
    /usr/bin/ld: cannot find -lstdc++ -lz问题
    linux下条件变量使用笔记
    map使用笔记
    关于友元函数在类内定义的问题--笔记
  • 原文地址:https://www.cnblogs.com/candy99/p/6783153.html
Copyright © 2020-2023  润新知