• AtCoder Grand Contest 001F Wide Swap


    解法参考这位大佬的:https://www.cnblogs.com/BearChild/p/7895719.html

     因为原来的数组不好做于是我们想反过来数组,根据交换条件:值相邻且位置差大于等于k,那么在变换后的数组就变成了位置相邻且差值大于等于k。这样的话变换操作变成了,相邻的大于等于k的值临近交换,于是我们注意到因为现在只能临近交换的原因,两个差值小于k的数他们的相对位置不可能发生改变。那么问题就变成了,在只有一些相对位置限制条件下,无限制的可以随意交换位置,求这个数组的最小字典序(原数组字典序最小也是现在数组字典序最小)。那么我们容易想到拓扑排序。

    但是如果每个点都想后面差值小于k的点连边的话,这个图会变得十分巨大,时间无法承受。于是我们必循得考虑优化建图:我们注意到像a->b,b->c,a->c这种建图,a->c这条边是不必要的。于是我们想办法避免掉这种无意义的边,所以对于某个点,我们让它向后面的所有限制(即差值小于k)中只向最小的那一个点连边,那么用线段树维护这样的信息,这样就达到优化建图的目的。

    这样只向最小的连边为什么是对的呢?借用上面大佬的一句话:倒着加入,显然 p_i 连向 (p_i-k, p_i)∪(p_i, p_i+k)。我们只需要分别连向两个区间中下标最小的那一个即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5+10;
    const int INF=0x3f3f3f3f;
    int n,k,tot,a[N],pos[N],deg[N],ans[N];
    set<int> L,R;
    vector<int> G[N];
    
    priority_queue<int> q;
    void toposort() {
        for (int i=1;i<=n;i++)
            if (deg[i]==0) q.push(-i);
        while (!q.empty()) {
            int x=-q.top(); q.pop();
            a[++tot]=x;
            for (int i=0;i<G[x].size();i++) {
                int y=G[x][i];
                if (--deg[y]==0) q.push(-y);
            }
        }    
    }
    
    int Min[N<<2];
    void build(int rt,int l,int r) {
        Min[rt]=INF;
        if (l==r) return;
        int mid=l+r>>1;
        build(rt<<1,l,mid); build(rt<<1|1,mid+1,r);
    }
    
    void update(int rt,int l,int r,int q,int v) {
        if (l==r) { Min[rt]=min(Min[rt],v); return; }
        int mid=l+r>>1;
        if (q<=mid) update(rt<<1,l,mid,q,v);
        if (q>mid) update(rt<<1|1,mid+1,r,q,v); 
        Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
    }
    
    int query(int rt,int l,int r,int ql,int qr) {
        if (ql<=l && r<=qr) return Min[rt];
        int mid=l+r>>1;
        int ret=INF;
        if (ql<=mid) ret=min(ret,query(rt<<1,l,mid,ql,qr));
        if (qr>mid) ret=min(ret,query(rt<<1|1,mid+1,r,ql,qr));
        return ret; 
    }
    
    int main()
    {
        cin>>n>>k;
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (int i=1;i<=n;i++) pos[a[i]]=i;
        
        build(1,1,n);
        for (int i=n;i;i--) {
            int t1=query(1,1,n,max(1,pos[i]-k+1),pos[i]);
            if (t1<=n) G[pos[i]].push_back(pos[t1]),deg[pos[t1]]++;
            int t2=query(1,1,n,pos[i],min(n,pos[i]+k-1));
            if (t2<=n) G[pos[i]].push_back(pos[t2]),deg[pos[t2]]++;
            update(1,1,n,pos[i],i);
        }
        
        toposort();
        for (int i=1;i<=n;i++) ans[a[i]]=i;  //最后记得把答案反过来 
        for (int i=1;i<=n;i++) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    dblink
    linux 查进程、杀进程、起进程
    oracle 资源统计SQL语句
    DIV+CSS+javascript 手动轮播图
    接受同步数据接口
    java String StringBuffer StringBuilder
    SpringMVC Servlet 分页查询接收参数
    WPF 开发
    收集整理的各地精品青年旅舍大全(
    Linux平台Java调用so库JNI使用例子
  • 原文地址:https://www.cnblogs.com/clno1/p/10832579.html
Copyright © 2020-2023  润新知