zoukankan      html  css  js  c++  java
  • 【题解】AT1984 Wide Swap(拓扑排序)

    【题解】AT1984 Wide Swap(拓扑排序)

    排列问题的一大套路是考虑arc数组(arc[data[t]]=t)

    然后题目那个swap的性质,就转换为了对于arc数组相邻的值,若其差大于等于(k)则可以交换,否则不能。

    考虑arc数组上任意两个数(x,y)(假设x的位置<y的位置)能够交换的条件,条件就是在(x,y)之间不存在和他们的差小于(k)的数。但如果有的话,那么(x,y)永远也不能交换了。也就是说,最终答案中,位置为(x)的数一定会小于位置(y)的数。

    "一定小于"关系会形成一个DAG,规定若(y->x)表示(x)位置上的数一定要比y的小。满足这个DAG的所有方案都是合法方案。一个生成合法方案的算法是在这个DAG上按拓扑一个个剥点,并且剥点时要分配递增的标号,这就相当于得到一个拓扑序,并且使得第(1)小的点尽量靠前,然后再满足第二大的尽量靠前...这就变成了HNOI菜肴制作了。

    考虑复杂度的问题,暴力(O(n^2))枚举不行的,可以发现若(x,y)不能交换且(y,z)不能交换,那么(x,z)不能交换(z的位置大于y的位置),所以只要连接一下那个下标最小的y就行了。

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
    	int ret=0,f=0,c=getchar();
    	while(!isdigit(c))f|=c==45,c=getchar();
    	while(isdigit(c)) ret=ret*10+c-48,c=getchar();
    	return f?-ret:ret;
    }
    
    const int maxn=5e5+5;
    const int inf=0x3f3f3f3f;
    vector<int> e[maxn];
    int data[maxn],arc[maxn],dr[maxn],n,k;
    int seg[maxn<<2],ans[maxn];
    void pp(int pos){seg[pos]=min(seg[pos<<1],seg[pos<<1|1]);}
    void add(int fr,int to){e[to].push_back(fr);++dr[fr];}
    
    #define mid ((l+r)>>1)
    #define lef l,mid,pos<<1
    #define rgt mid+1,r,pos<<1|1
    int que(int L,int R,int l,int r,int pos){
    	if(L>r||R<l) return inf;
    	if(L<=l&&r<=R) return seg[pos];
    	return min(que(L,R,lef),que(L,R,rgt));
    }
    void upd(int p,int v,int l,int r,int pos){
    	if(p<l||p>r) return;
    	if(l==r) return seg[pos]=v,void();
    	upd(p,v,lef); upd(p,v,rgt);
    	pp(pos);
    }
    #undef mid
    #undef lef
    #undef rgt
    
    int main(){
    	n=qr(); k=qr();
    	for(int t=1;t<=n;++t) data[t]=qr(),arc[data[t]]=t;
    	memset(seg,0x3f,sizeof seg);
    	for(int t=n;t;--t){
    		int t1=que(arc[t]-k+1,arc[t]-1,1,n,1);
    		int t2=que(arc[t]+1,arc[t]+k-1,1,n,1);
    		if(t1<=n) add(arc[t],arc[t1]);
    		if(t2<=n) add(arc[t],arc[t2]);
    		upd(arc[t],t,1,n,1);
    	}
    	static priority_queue<int> q;
    	for(int t=1;t<=n;++t)
    		if(!dr[t]) q.push(t);
    	int cnt=0;
    	while(q.size()){
    		int now=q.top();
    		ans[now]=++cnt;
    		q.pop();
    		for(auto t:e[now])
    			if(--dr[t]==0)
    				q.push(t);
    	}
    	for(int t=1;t<=n;++t) printf("%d
    ",n-ans[t]+1);
    	return 0;
    }
    
  • 相关阅读:
    GitHub入门教程
    转:使用ActiveX插件时object显示问题,div被object标签遮挡的解决方案
    windows集成资料
    转:获取windows凭证管理器明文密码
    转: OVER() 系列函数介绍
    SQL Prompt 快捷键
    转:敏捷开发之Scrum扫盲篇
    转:修改IIS虚拟目录名称bat脚本
    转:EditPuls 5.0 注册码
    转:RowVersion 用法
  • 原文地址:https://www.cnblogs.com/winlere/p/12241542.html
Copyright © 2011-2022 走看看