HZOJ Permutation
输出原序列有45分……
字典序最小可以和拓扑序联系起来。
根据原来的题意不是很可做,于是对原序列求逆,令q[p[i]]=i;
那么就成功将题意转化:相邻元素值的差大于等于k时可以交换,使序列字典序最小。
考虑一下$n^2$怎么做,对于$i<j$,如果$abs(q[i]-q[j])<k$,那么q[i]和q[i]的大小关系不会发生变化,那么连一条$q[i]->q[j]$的边表示q[i]在q[j]之前,跑拓扑排序就可以了。
考虑优化,其实做过很多这种题了(‘炸弹’),图中会存在$A->B,B->C,A->C$之类的边,显然$A->C$可以去掉。怎么实现呢?对于一个q[i],是向右边差小于k的连边,那么其实只需要连两条边,即离他最近的大于他的和小于他的,那么其它的点也会被他们限制。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<queue> 6 #define LL long long 7 using namespace std; 8 struct edge 9 { 10 int u,v,nxt; 11 #define u(x) ed[x].u 12 #define v(x) ed[x].v 13 #define n(x) ed[x].nxt 14 }ed[10000010]; 15 int first[500010],num_e; 16 #define f(x) first[x] 17 int n,k,p[500010],q[500010],du[500010]; 18 struct TREE 19 { 20 struct tree 21 { 22 int l,r,ls,rs,minn; 23 #define l(x) tr[x].l 24 #define r(x) tr[x].r 25 #define ls(x) tr[x].ls 26 #define rs(x) tr[x].rs 27 #define minn(x) tr[x].minn 28 }tr[10000000]; 29 int cnt,root; 30 void build(int &x,int l,int r) 31 { 32 if(!x)x=++cnt; 33 l(x)=l,r(x)=r,minn(x)=0x7fffffff; 34 if(l==r)return; 35 int mid=(l+r)>>1; 36 build(ls(x),l,mid); 37 build(rs(x),mid+1,r); 38 } 39 void add(int x,int pos,int y) 40 { 41 // cout<<x<<" "<<l(x)<<" "<<r(x)<<" "<<pos<<" "<<y<<endl; 42 if(l(x)==r(x)){minn(x)=y;return;} 43 int mid=(l(x)+r(x))>>1; 44 if(pos<=mid)add(ls(x),pos,y); 45 else add(rs(x),pos,y); 46 minn(x)=min(minn(ls(x)),minn(rs(x))); 47 } 48 int ask(int x,int l,int r) 49 { 50 if(l(x)>=l&&r(x)<=r)return minn(x); 51 int mid=(l(x)+r(x))>>1,ans=0x7fffffff; 52 if(l<=mid)ans=min(ans,ask(ls(x),l,r)); 53 if(r> mid)ans=min(ans,ask(rs(x),l,r)); 54 return ans; 55 } 56 }T; 57 inline void add(int u,int v); 58 signed main() 59 { 60 cin>>n>>k;T.build(T.root,1,n); 61 for(int i=1;i<=n;i++) 62 cin>>p[i],q[p[i]]=i; 63 64 // for(int i=1;i<=n;i++)cout<<q[i]<<" ";puts(""); 65 for(int i=n;i;--i) 66 { 67 int t1=T.ask(1,max(1,q[i]-k+1),min(n,q[i]-1)), 68 t2=T.ask(1,max(1,q[i]+1),min(n,q[i]+k-1)); 69 // cout<<i<<" "<<t1<<" "<<t2<<" "<<q[i]<<endl; 70 if(t1!=0x7fffffff)add(q[i],q[t1]),du[q[t1]]++; 71 if(t2!=0x7fffffff)add(q[i],q[t2]),du[q[t2]]++; 72 T.add(1,q[i],i); 73 } 74 75 priority_queue<int,vector<int>,greater<int> >que; 76 for(int i=1;i<=n;i++)if(!du[i])que.push(i); 77 int cnt=0; 78 while(!que.empty()) 79 { 80 int x=que.top();q[++cnt]=x;que.pop(); 81 for(int i=f(x);i;i=n(i)) 82 { 83 du[v(i)]--; 84 if(!du[v(i)])que.push(v(i)); 85 } 86 } 87 for(int i=1;i<=n;i++)p[q[i]]=i; 88 89 for(int i=1;i<=n;i++)cout<<p[i]<<endl; 90 } 91 inline void add(int u,int v) 92 { 93 // cout<<"add: "<<u<<" "<<v<<endl; 94 ++num_e; 95 u(num_e)=u; 96 v(num_e)=v; 97 n(num_e)=f(u); 98 f(u)=num_e; 99 }
%%mikufun权值线段树优化建边。
波澜前,面不惊。