AGC001F Wide Swap

Link
首先进行一个转换,我们构造\(q\)使得\(q_{p_i}=i\),那么最小化\(p\)的字典序实质上就是最小化\(q\)的字典序。
然后题目给的限制就变成了只能交换\(q_i,q_{i+1}(|q_i-q_{i+1}|\le k)\),等价于满足\(|q_i-q_j|\le k(i<j)\)\(q_i,q_j\)的相对位置不变。
这样我们就可以\(q_i\rightarrow q_j\)表示\(q_i\)必须在\(q_j\)前面,然后求最小拓扑序。
直接建边是\(O(n^2)\)的,我们可以对每个\(q_i\),只向\(j>i\)\(q_j\in[q_i-k+1,q_i-1]\)\(q_j\in[q_i+1,q_i+k-1]\)中最近的两个连边,显然这样连边对偏序关系是没有影响的。
具体而言可以从后往前做,用线段树维护一下就好了。

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<functional>
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    void write(int x){int top=0;while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}using namespace IO;
using std::vector;
using std::priority_queue;
int min(int a,int b){return a<b? a:b;}
const int N=500007,inf=0x7f7f7f7f;
vector<int>e[N];priority_queue<int,vector<int>,std::greater<int>>Q;
int n,k,p[N],q[N],mn[N<<2],deg[N];
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
void pushup(int p){mn[p]=min(mn[ls],mn[rs]);}
void update(int p,int l,int r,int x,int v)
{
    if(r==l) return (void)(mn[p]=v);
    (x<=mid? update(ls,l,mid,x,v):update(rs,mid+1,r,x,v)),pushup(p);
}
int query(int p,int l,int r,int L,int R)
{
    if(r<L||R<l) return inf;
    if(L<=l&&r<=R) return mn[p];
    return min(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R));
}
int main()
{
    int n=read(),k=read(),m=0;memset(mn,0x7f,sizeof mn);
    for(int i=1;i<=n;++i) q[read()]=i;
    for(int i=n,j;i;--i)
    {
    if((j=query(1,1,n,q[i]+1,q[i]+k-1))^inf) ++deg[q[j]],e[q[i]].push_back(q[j]);
    if((j=query(1,1,n,q[i]-k+1,q[i]-1))^inf) ++deg[q[j]],e[q[i]].push_back(q[j]);
    update(1,1,n,q[i],i);
    }
    for(int i=1;i<=n;++i) if(!deg[i]) Q.push(i);
    for(int u;!Q.empty();)
    {
    q[++m]=u=Q.top(),Q.pop();
    for(int v:e[u]) if(!--deg[v]) Q.push(v);
    }
    for(int i=1;i<=n;++i) p[q[i]]=i;
    for(int i=1;i<=n;++i) write(p[i]);
    return Flush(),0;
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/12233486.html