成功拿到 LOJ 上除 HeRaNO 的一血,爽啦。
然而常數是他的四倍,代碼長度是他的兩倍,還調sb錯誤調了一上午
T2 是個簡單構造,T3 是個模擬費用流(裸題?),就不寫了。
思路
先盯着這個 \(2k>n\) 看,它有什么性質呢?
發現 \(2k>n\) 時排列是唯一的:從大到小確定每個數的位置,那么 \(n\) 一定在 \(r=0\) 的位置,而 \(r=0\) 的位置顯然會在一個劣弧上(不然就無解了),所以 \(n\) 只能在一個端點上。確定 \(n\) 后給它前面的 \(r\) 減一,繼續操作。
更嚴謹地說,每次是挑出一個 0 ,使得前一個 0 和它的距離超過 \(k\) ,把當前的最大值放在那里。
然而這個結論顯然不能擴展到 \(k\) 小的情況,因為這時候可能有很多合法的 0 。
性質一:每次任取一個合法的 0 填入最大值,一定可以構造出一個合法的排列。
證明:已知存在一個合法的排列。在某個時刻,可以把還沒填數的位置按照在合法排列中的大小順序從大到小填入剩下的數,那么可以發現(反證)每次填的位置都是一個合法的 0 。
暴力構造排列是 \(O(n^2)\) 的,但可以用線段樹+set+雙堆做到 \(O(n\log n)\) 。
性質二:一個排列合法等價於每連續 \(k\) 個數之間的大小關系與構造出的那個排列相同。
證明:同樣可以反證。
根據條件可以得到一個 DAG ,那么 \((x,y)\) 的大小關系能夠確定當且僅當 \(x\) 能到達 \(y\) (或反過來)。然而暴力連邊跑傳遞閉包顯然不太行。
設連邊是小向大連,那么可以發現一個點 \(x\) 其實只需要連兩條邊,分別向 \((x-K,x-1],[x+1,x+K)\) 里面比 \(x\) 大的最小的點連邊。判斷的時候就是分別往兩個方向跳,看跳到 \(y\) 旁邊的時候是否還比 \(y\) 小。
由於一個方向只有一條邊,所以倍增即可。
代碼
丑死了。
#include<bits/stdc++.h>
#include "plants.h"
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 402020
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifdef NTFOrz
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,K;
int r[sz],p[sz],id[sz];
namespace SGT
{
int mn[sz<<2],tag[sz<<2];
#define ls k<<1
#define rs k<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
void Tag(int k,int w){tag[k]+=w,mn[k]+=w;}
void pushdown(int k){int &t=tag[k];Tag(ls,t),Tag(rs,t);t=0;}
void pushup(int k){mn[k]=min(mn[ls],mn[rs]);}
void modify(int k,int l,int r,int x,int y,int w)
{
if (x<=l&&r<=y) return Tag(k,w);
int mid=(l+r)>>1; pushdown(k);
if (x<=mid) modify(lson,x,y,w);
if (y>mid) modify(rson,x,y,w);
pushup(k);
}
int query(int k,int l,int r)
{
if (l==r) return l;
int mid=(l+r)>>1; pushdown(k);
if (mn[ls]==0) return query(lson);
return query(rson);
}
int qmin(int k,int l,int r,int x,int y)
{
if (x<=l&&r<=y) return mn[k];
int mid=(l+r)>>1,res=1e9; pushdown(k);
if (x<=mid) chkmin(res,qmin(lson,x,y));
if (y>mid) chkmin(res,qmin(rson,x,y));
return res;
}
int query(int k,int l,int r,int x,int y,int w)
{
int mid=(l+r)>>1; if (l!=r) pushdown(k);
if (mn[k]>w) return -1;
if (x<=l&&r<=y)
{
if (l==r) return l;
if (mn[ls]==w) return query(lson,x,y,w); return query(rson,x,y,w);
}
int res=-1;
if (x<=mid) res=query(lson,x,y,w); if (res!=-1) return res;
if (y>mid) res=query(rson,x,y,w);
return res;
}
int qry(int l,int r){int w=qmin(1,0,n+n-1,l,r);return w>n?1e9:query(1,0,n+n-1,l,r,w);}
void build(int k,int l,int r,int tp)
{
tag[k]=0;
if (l==r) return mn[k]=tp?::r[l]:1e9,void();
int mid=(l+r)>>1;
build(lson,tp),build(rson,tp); pushup(k);
}
}
using namespace SGT;
namespace Set_Pq
{
set<int>s;
priority_queue<pii>q1,q2;
void maintain(){while (q1.size()&&q2.size()&&q1.top()==q2.top()) q1.pop(),q2.pop();}
void insert(int x)
{
s.insert(x); auto it=s.find(x);
if (s.size()==1u) return q1.push(MP(n,x)),void();
int l,r;
if (it==s.begin()) l=*prev(s.end())-n; else l=*prev(it);
if (next(it)==s.end()) r=*(s.begin())+n; else r=*next(it);
q2.push(MP(r-l,r%n)); q1.push(MP(r-x,r%n)),q1.push(MP(x-l,x));
}
void del(int x)
{
auto it=s.find(x);
if (s.size()==1u) return s.erase(it),q2.push(MP(n,x)),void();
int l,r;
if (it==s.begin()) l=*prev(s.end())-n; else l=*prev(it);
if (next(it)==s.end()) r=*(s.begin())+n; else r=*next(it);
q1.push(MP(r-l,r%n)); q2.push(MP(r-x,r%n)),q2.push(MP(x-l,x));
s.erase(it);
}
}
int jl[sz][21],jr[sz][21];
int ok(int x,int y){return (x>=0&&x<=n+n-1)?x:y;}
void init(int _k,vector<int>R)
{
n=R.size(),K=_k; rep(i,0,n-1) r[i]=R[i],p[i]=-1;
SGT::build(1,0,n-1,1);
drep(_,n-1,0)
{
int x;
while (mn[1]==0) x=query(1,0,n-1),modify(1,0,n-1,x,x,1e9),Set_Pq::insert(x);
Set_Pq::maintain();
x=Set_Pq::q1.top().sec;
p[x]=_; Set_Pq::del(x);
if (x>=K-1) modify(1,0,n-1,x-K+1,x,-1); else modify(1,0,n-1,0,x,-1),modify(1,0,n-1,n+1-K+x,n-1,-1);
}
rep(i,0,n-1) id[p[i]]=i; build(1,0,n+n-1,0);
drep(i,n-1,0)
{
int x=id[i];
int pr=qry(x+1,x+K-1),pl=qry(x+n-K+1,x+n-1)-n;
jl[x][0]=ok(pl,x),jr[x][0]=ok(pr,x);
jl[x+n][0]=ok(pl+n,x+n),jr[x+n][0]=ok(pr+n,x+n);
modify(1,0,n+n-1,x,x,i-1e9),modify(1,0,n+n-1,x+n,x+n,i-1e9);
}
rep(j,1,20) rep(i,0,n+n-1) jl[i][j]=jl[jl[i][j-1]][j-1];
rep(j,1,20) rep(i,0,n+n-1) jr[i][j]=jr[jr[i][j-1]][j-1];
}
int check(int x,int y)
{
if (x<y) { drep(i,20,0) if (jr[x][i]<=y) x=jr[x][i]; }
else { drep(i,20,0) if (jl[x][i]>=y) x=jl[x][i]; }
return abs(x-y)<K&&p[x%n]<=p[y%n];
}
int compare_plants(int x,int y)
{
if (min((x-y+n)%n,(y-x+n)%n)<K) return p[x]<p[y]?-1:1;
int _x=x,_y=y;
if (p[x]>p[y]) swap(x,y);
if (!check(x,y)&&!check(x+n*(x<y),y+n*(y<x))) return 0;
return p[_x]<p[_y]?-1:1;
}