zoukankan      html  css  js  c++  java
  • AGC 001 F Wide swap [思维题+线段树优化]

    Wide swapWide swap


    color{blue}{最初想法}

    对于 Ai<AjA_i < A_j 的点对 i,ji, j, 不会出现 AiA_iAjA_j 交换后, AiA_iAjA_j 在 后面的情况 .


    color{red}{正解部分}

    新建一个数组 B[]B[], 使得 B[A[i]]=iB[A[i]] = i,
    则要求 A[]A[] 排列字典序最小的问题 就转化成了 使要求 B[]B[] 字典序最小的问题,
    且交换条件为:

    1. 位置相邻 .
    2. 权值差大于等于 KK .

    考虑两个元素 Bi,BjB_i, B_j, 若 i<ji < j, BiBj<KB_i - B_j < K, 则 iijj 的相对位置不可改变,
    此时若 iijj 连边, 建图后可以使用 拓扑排序 可以确定最小字典序数列 .


    但是这样建图的时空复杂度是 O(N2)O(N^2) 的, 需要加以优化 .

    注意到在拓扑排序中, 当 aba ightarrow b, bcb ightarrow c, 则 aca ightarrow c 是无意义的, 从这方面来优化 .

    具体来说:
    从后往前遍历, 设当前位置为 ii, 则 B[i]B[i] 向 值属于(B[i]K,B[i])(B[i],B[i]+K)(B[i]-K, B[i])∪(B[i], B[i]+K) 中 存在的 最小编号的 B[j]B[j] 连边 .


    color{red}{实现部分}

    • 注意线段树中的节点是以B[]B[]值为下标, B[]B[]下标为值的
    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 500005;
    const int inf = 0x3f3f3f3f;
    
    int N;
    int K;
    int num0;
    int A[maxn];
    int B[maxn];
    int In_d[maxn];
    int head[maxn];
    int top_A[maxn];
    
    struct Segment_Tree{
            struct Node{ int l, r, min_v; } T[maxn<<2];
            void Build(int k, int l, int r){
                    T[k].l = l, T[k].r = r, T[k].min_v = inf;
                    if(l == r) return ;
                    int mid = l+r >> 1;
                    Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
            }
            int Query(int k, const int &ql, const int &qr){
                    int l = T[k].l, r = T[k].r;
                    if(ql <= l && r <= qr) return T[k].min_v;
                    int mid = l+r >> 1;
                    int s = inf;
                    if(ql <= mid) s = Query(k<<1, ql, qr);
                    if(qr > mid) s = std::min(s, Query(k<<1|1, ql, qr));
                    return s;
            }
            void Insert(int k, int aim, int v){
                    int l = T[k].l, r = T[k].r;
                    if(l == r){ T[k].min_v = v; return ; }
                    int mid = l+r >> 1;
                    if(aim <= mid) Insert(k<<1, aim, v);
                    else Insert(k<<1|1, aim, v);
                    T[k].min_v = std::min(T[k<<1].min_v, T[k<<1|1].min_v);
            }
    } Seg_t;
    
    struct Edge{ int nxt, to; } edge[maxn << 1];
    
    void Add(int from, int to){
            edge[++ num0] = (Edge){ head[from], to };
            head[from] = num0;
    }
    
    void Link(){
            Seg_t.Build(1, 1, N);
            for(reg int i = N; i >= 1; i --){
                    int res = Seg_t.Query(1, std::max(1, B[i]-K+1), B[i]);
                    if(res <= N) Add(B[i], B[res]), In_d[B[res]] ++;
                    res = Seg_t.Query(1, B[i], std::min(N, B[i]+K-1));
                    if(res <= N) Add(B[i], B[res]), In_d[B[res]] ++;
                    Seg_t.Insert(1, B[i], i);
            }
    }
    
    void Topsort(){
            std::priority_queue <int> Q;
            for(reg int i = 1; i <= N; i ++) if(!In_d[i]) Q.push(-i);
            int cnt = 0;
            while(!Q.empty()){
                    int ft = -Q.top(); Q.pop();
                    top_A[++ cnt] = ft;
                    for(reg int i = head[ft]; i; i = edge[i].nxt){
                            int to = edge[i].to;
                            if((-- In_d[to]) == 0) Q.push(-to);
                    }
            }
    }
    
    int main(){
            N = read(), K = read();
            for(reg int i = 1; i <= N; i ++) A[i] = read(), B[A[i]] = i;
            Link(); Topsort();
            for(reg int i = 1; i <= N; i ++) A[top_A[i]] = i;
            for(reg int i = 1; i <= N; i ++) printf("%d
    ", A[i]);
            return 0;
    }
    
  • 相关阅读:
    jquery实现选项卡(两句即可实现)
    常用特效积累
    jquery学习笔记
    idong常用js总结
    织梦添加幻灯片的方法
    LeetCode "Copy List with Random Pointer"
    LeetCode "Remove Nth Node From End of List"
    LeetCode "Sqrt(x)"
    LeetCode "Construct Binary Tree from Inorder and Postorder Traversal"
    LeetCode "Construct Binary Tree from Preorder and Inorder Traversal"
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822502.html
Copyright © 2011-2022 走看看