首页 > 编程语言 > 详细

AGC001 F - Wide Swap【线段树+堆+拓扑排序】

时间:2019-05-26 22:35:31      阅读:154      评论:0      收藏:0      [点我收藏+]

给出的模型很难搞,所以转换一下,记p[i]为i这个数的位置,然后相邻两个p值差>k的能交换,发现使原问题字典序最小也需要使这里的字典序最小
注意到p值差<=k的前后顺序一定不変,那么可以n^2建图用堆跑最小字典序拓扑序
考虑优化,每个点需要向[p[i]-k+1,p[i]+k-1]这段区间的数连边,但是有一些边是多余的,也就是区间[p[i]-k+1,p[i]],[p[i],p[i]+k-1]这两个区间内的数一定两两有边所以连向当前点后面最近的一个即可,这个用线段树来找

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=3000005;
int n,k,a[N],p[N],h[N],cnt,d[N],tot;
struct xds
{
    int l,r,p;
}t[N];
struct qwe
{
    int ne,to;
}e[N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void build(int ro,int l,int r)
{
    t[ro].l=l,t[ro].r=r,t[ro].p=n+1;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(ro<<1,l,mid);
    build(ro<<1|1,mid+1,r);
}
void update(int ro,int p,int v)
{
    if(t[ro].l==t[ro].r)
    {
        t[ro].p=v;
        return;
    }
    int mid=(t[ro].l+t[ro].r)>>1;
    if(p<=mid)
        update(ro<<1,p,v);
    else
        update(ro<<1|1,p,v);
    t[ro].p=min(t[ro<<1].p,t[ro<<1|1].p);
}
int ques(int ro,int l,int r)
{
    if(t[ro].l==l&&t[ro].r==r)
        return t[ro].p;
    int mid=(t[ro].l+t[ro].r)>>1;
    if(r<=mid)
        return ques(ro<<1,l,r);
    else if(l>mid)
        return ques(ro<<1|1,l,r);
    else
        return min(ques(ro<<1,l,mid),ques(ro<<1|1,mid+1,r));
}
void add(int u,int v)
{//cerr<<u<<" "<<v<<endl;
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    d[v]++;
    h[u]=cnt;
}
int main()
{
    n=read(),k=read();
    for(int i=1;i<=n;i++)
        a[i]=read(),p[a[i]]=i;
    build(1,1,n);
    for(int i=n;i>=1;i--)
    {
        int x=ques(1,p[i],min(n,p[i]+k-1)),y=ques(1,max(1,p[i]-k+1),p[i]);
        if(x<=n)
            add(p[i],p[x]);
        if(y<=n)
            add(p[i],p[y]);
        update(1,p[i],i);
    }
    priority_queue<int,vector<int>,greater<int> >q;
    for(int i=1;i<=n;i++)
        if(!d[i])
            q.push(i);
    while(!q.empty())
    {
        int u=q.top();
        p[++tot]=u;
        q.pop();
        for(int i=h[u];i;i=e[i].ne)
            if(!(--d[e[i].to]))
                q.push(e[i].to);
    }
    for(int i=1;i<=n;i++)
        a[p[i]]=i;
    for(int i=1;i<=n;i++)
        printf("%d\n",a[i]);
    return 0;
}

AGC001 F - Wide Swap【线段树+堆+拓扑排序】

原文:https://www.cnblogs.com/lokiii/p/10928043.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!