T1
題解:
代碼:
T2
題解:
很明顯我們可以轉化一下看看,貪心的從最小的開始選擇,每一個數字可以連向左邊還沒被擴進去的最大值,右邊的第一個,或者是自己,維護區間最大值可以用線段樹,維護哪些區間被用過可以用set。
則234被扎死口,234的值都是0;56未被扎死口,6的值是0。可以發現,被扎死口的元素值爲0,值爲0的元素不一定被扎死口,因爲還可以向左連5,這裏扎死口的概念就是能否越過這個點向左找值的意思
代碼:
#include <set>
#include <cstdio>
#include <iostream>
#define INF 1e9
using namespace std;
const int N=100005;
set<int>s;int maxx[N*4],a[N],pos[N],n,ans[N];
void updata(int now){maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);}
void change(int now,int l,int r,int x,int v)
{
if (l==r){maxx[now]=v;return;}
int mid=(l+r)>>1;
if (x<=mid) change(now<<1,l,mid,x,v);
else change(now<<1|1,mid+1,r,x,v);
updata(now);
}
int qurry(int now,int l,int r,int lrange,int rrange)
{
if (lrange>rrange) return 0;
if (lrange<=l && rrange>=r) return maxx[now];
int mid=(l+r)>>1,ans=0;
if (lrange<=mid) ans=qurry(now<<1,l,mid,lrange,rrange);
if (rrange>mid) ans=max(ans,qurry(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}
void bl(int l,int r)
{
for (int i=l;i<=r;i++)
change(1,1,n,i,0),s.insert(i);
int z=r-l+1;
for (int i=0;i<=r-l;i++) ans[a[l+(i-1+z)%z]]=a[l+i];
}
int main()
{
freopen("perm.in","r",stdin);
freopen("perm.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) pos[a[i]]=i;
for (int i=1;i<=n;i++) change(1,1,n,pos[i],i);
s.insert(0);
for (int i=1;i<=n;i++)
if (!ans[i])
{
int wz=0,now=pos[i],maxx=0,zuo;
wz=*--s.lower_bound(now);
if (qurry(1,1,n,now,now)!=0) maxx=i,zuo=now;
//可能已經被選了(被向右擴的結果 ,不能用s.count的原因是這個點不一定被扎死口,可能後邊的還向前連
//被扎死口的一定是0,0的不一定被扎死口
if (!s.count(now+1)) //右邊的已經被選過了
{
if (maxx<a[now+1]) maxx=a[now+1],zuo=now+1;
}
if (wz+1<=now-1)
{
int z=qurry(1,1,n,wz+1,now-1);
if (maxx<z) maxx=z,zuo=pos[z];
}
if (zuo==now)
{
s.insert(now);change(1,1,n,now,0);
ans[i]=i;
continue;
}
if (zuo==now+1)
{
change(1,1,n,now+1,0);
continue;
}
bl(zuo,now);
}
for (int i=1;i<=n;i++) printf("%d ",ans[i]);
}