结论:设$b_{i}$满足该限制,则$a_{i}$合法当且仅当$forall i e j,a_{i} e a_{j}$且$forall |i-j|<k,[a_{i}<a_{j}]=[b_{i}<b_{j}]$,即$r_{i}$可以确定任意连续$k$位的相对大小关系
充分性显然成立,必要性不会证QAQ
构造$b_{i}$:考虑从0到$n-1$依次填写,每次填写的位置$x$需要满足:1.$r_{x}=k-1$;2.$forall i-k<j<i,r_{j} e k-1$
第一个条件能够保证之后的$k-1$个数都比其小,第二个条件能保证之前的$k-1$个数都比其小(令$y$为前$k-1$个数中的最小值,再反证即可),因此这样是正确的
对于第2个条件的判定,可以找出所有满足$r_{x}=k-1$的点组成一个set,在对这个set插入或删除的同时,找出所有满足第2个条件的点再组成一个set(因为还要删除)即可
找到这样的位置后,填上当前的数,并令:1.$r_{x}=-infty$(保证自己不再被选);2.$forall i-k<j<i,r_{j}+=1$
建图:对于每一个数$i$,设其前$k-1$个数中前驱后继为$pre$和$nex$,连有向边$(nex,i)$和$(i,pre)$,之后$a_{x}>a_{y}$当且仅当$x$能走到$y$
虽然这张图并不一定是一条链,但不妨将所有边分为两类,向前(即$(nex,i)$)和向后(即$(i,pre)$)(并不是仅仅比较两数大小),那么如果存在路径,必然存在一条只走向前/向后的路径,使得能够到达$y$周围的$k$个位置,因此对两种路径分别倍增维护即可
1 #include "plants.h" 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define N 200005 5 #define oo 0x3f3f3f3f 6 #define L (k<<1) 7 #define R (L+1) 8 #define mid (l+r>>1) 9 set<int>se; 10 set<int>::iterator itt; 11 set<pair<int,int> >s; 12 set<pair<int,int> >::iterator it; 13 int n,k,a[N],r[N],tag[N<<2],f[N<<2],fa[2][N][21],d[2][N][21]; 14 void upd(int k,int x){ 15 tag[k]+=x; 16 f[k]+=x; 17 } 18 void down(int k){ 19 upd(L,tag[k]); 20 upd(R,tag[k]); 21 tag[k]=0; 22 } 23 void update(int k,int l,int r,int x,int y,int z){ 24 if ((l>y)||(x>r))return; 25 if ((x<=l)&&(r<=y)){ 26 upd(k,z); 27 return; 28 } 29 down(k); 30 update(L,l,mid,x,y,z); 31 update(R,mid+1,r,x,y,z); 32 f[k]=max(f[L],f[R]); 33 } 34 int query(int k,int l,int r){ 35 if (l==r)return l; 36 down(k); 37 if (f[L]==f[k])return query(L,l,mid); 38 return query(R,mid+1,r); 39 } 40 bool pd(int x){ 41 if (x>=k-1)return (*se.upper_bound(x-k))==x; 42 return (x==(*se.begin()))&&(se.upper_bound(x-k+n)==se.end()); 43 } 44 void add(int x){ 45 itt=se.upper_bound(x); 46 if (itt==se.end())itt=se.begin(); 47 int y=(*itt); 48 if (pd(y))s.erase(make_pair(y,0)); 49 se.insert(x); 50 if (pd(x))s.insert(make_pair(x,0)); 51 if (pd(y))s.insert(make_pair(y,0)); 52 } 53 void del(int x){ 54 se.erase(x); 55 itt=se.upper_bound(x); 56 if (itt==se.end())itt=se.begin(); 57 if (pd(*itt))s.insert(make_pair((*itt),0)); 58 } 59 int dis(int x,int y){ 60 if (x<=y)return y-x; 61 return y+n-x; 62 } 63 void init(int kk,vector<int>rr){ 64 n=rr.size(); 65 k=kk; 66 for(int i=0;i<n;i++)r[i]=rr[i]; 67 for(int i=0;i<n;i++)update(1,0,n-1,i,i,r[i]); 68 for(int i=0;i<n;i++){ 69 while (f[1]==k-1){ 70 int x=query(1,0,n-1); 71 add(x); 72 update(1,0,n-1,x,x,-oo); 73 } 74 int x=(*s.begin()).first; 75 s.erase(s.begin()); 76 del(x); 77 a[x]=i; 78 if (x-k+1>=0)update(1,0,n-1,x-k+1,x-1,1); 79 else{ 80 update(1,0,n-1,0,x-1,1); 81 update(1,0,n-1,x-k+1+n,n-1,1); 82 } 83 } 84 for(int i=0;i<k;i++)s.insert(make_pair(a[i],i)); 85 for(int i=0;i<n;i++){ 86 s.erase(make_pair(a[i],i)); 87 it=upper_bound(s.begin(),s.end(),make_pair(a[i],i)); 88 if (it==s.end())fa[0][i][0]=i; 89 else fa[0][i][0]=(*it).second; 90 d[0][i][0]=dis(i,fa[0][i][0]); 91 it=upper_bound(s.begin(),s.end(),make_pair(a[(i+k)%n],(i+k)%n)); 92 if (it==s.end())fa[1][(i+k)%n][0]=(i+k)%n; 93 else fa[1][(i+k)%n][0]=(*it).second; 94 d[1][(i+k)%n][0]=dis(fa[1][(i+k)%n][0],(i+k)%n); 95 s.insert(make_pair(a[(i+k)%n],(i+k)%n)); 96 } 97 for(int p=0;p<2;p++) 98 for(int i=1;i<=20;i++) 99 for(int j=0;j<n;j++){ 100 fa[p][j][i]=fa[p][fa[p][j][i-1]][i-1]; 101 d[p][j][i]=min(d[p][j][i-1]+d[p][fa[p][j][i-1]][i-1],n); 102 } 103 } 104 bool pd(int x,int y){ 105 int dd=dis(x,y),z=x; 106 for(int i=20;i>=0;i--) 107 if (d[0][x][i]<=dd){ 108 dd-=d[0][x][i]; 109 x=fa[0][x][i]; 110 } 111 if ((dd<k)&&(a[x]<=a[y]))return 1; 112 dd=dis(y,x=z); 113 for(int i=20;i>=0;i--) 114 if (d[1][x][i]<=dd){ 115 dd-=d[1][x][i]; 116 x=fa[1][x][i]; 117 } 118 return ((dd<k)&&(a[x]<=a[y])); 119 } 120 int compare_plants(int x,int y){ 121 if ((a[x]<a[y])&&(pd(x,y)))return -1; 122 if ((a[x]>a[y])&&(pd(y,x)))return 1; 123 return 0; 124 }