E - Little Elephant and Shifts
思路:
一次函数线段树(疯狂debug);
b不断循环左移,判断每次最小的|i-j|,a[i]=b[j];
仔细观察发现,每个bi移动时,|i-j|呈现多个一次函数图像;
所以用线段树来维护这些一次函数图像;
线段树维护一次函数,当两个函数在区间没有交点时;
判断哪个在图像较下的位置,然后覆盖;
当有交点时,保留最优,将另一条传下去;
时间复杂度O(nlog^2n);
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 100005 #define INF 0x7fffffff struct TreeNodeType { int l,r,k,b,mid; bool if_; }; struct TreeNodeType tree[maxn<<2]; int n,ai[maxn],p[maxn],X; inline void in(int &now) { char Cget=getchar();now=0; while(Cget>'9'||Cget<'0') Cget=getchar(); while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } } void tree_build(int now,int l,int r) { tree[now].l=l,tree[now].r=r,tree[now].mid=l+r>>1; if(l==r) return ; tree_build(now<<1,l,tree[now].mid); tree_build(now<<1|1,tree[now].mid+1,r); } double com(int k1,int b1,int k2,int b2) { if(k1==k2) return 0; return (double)(b2-b1)/(double)(k1-k2); } void tree_down(int now,int k,int b) { if(!tree[now].if_) { tree[now].if_=true,tree[now].k=k,tree[now].b=b; return ; } double x=com(k,b,tree[now].k,tree[now].b); if(x<=tree[now].l||x>=tree[now].r) { double mid=(double)(tree[now].l+tree[now].r)/2; if(mid*k+b<mid*tree[now].k+tree[now].b) tree[now].k=k,tree[now].b=b; return ; } if(x<=tree[now].mid) { if(k>tree[now].k) tree_down(now<<1,k,b); else { tree_down(now<<1,tree[now].k,tree[now].b); tree[now].k=k,tree[now].b=b; } } else { if(k<tree[now].k) tree_down(now<<1|1,k,b); else { tree_down(now<<1|1,tree[now].k,tree[now].b); tree[now].k=k,tree[now].b=b; } } } void tree_add(int now,int l,int r,int k,int b) { if(tree[now].l==l&&tree[now].r==r) { if(tree[now].if_) { if(k==tree[now].k&&b==tree[now].b); else tree_down(now,k,b); } else tree[now].if_=true,tree[now].k=k,tree[now].b=b; return ; } if(l>tree[now].mid) tree_add(now<<1|1,l,r,k,b); else if(r<=tree[now].mid) tree_add(now<<1,l,r,k,b); else { tree_add(now<<1,l,tree[now].mid,k,b); tree_add(now<<1|1,tree[now].mid+1,r,k,b); } } void tree_query(int now,int to) { if(tree[now].if_) X=min(X,tree[now].k*to+tree[now].b); if(tree[now].l==tree[now].r) return ; if(to<=tree[now].mid) tree_query(now<<1,to); else tree_query(now<<1|1,to); } int main() { in(n);int pos,debug; for(int i=1;i<=n;i++) in(ai[i]); for(int i=1;i<=n;i++) in(pos),p[pos]=i; tree_build(1,1,n); for(int i=1;i<=n;i++) { if(i<p[ai[i]]) { tree_add(1,1,p[ai[i]]-i+1,-1,p[ai[i]]+1-i); if(i!=1) tree_add(1,p[ai[i]]-i+2,p[ai[i]],1,i-p[ai[i]]-1); if(p[ai[i]]!=n) tree_add(1,p[ai[i]]+1,n,-1,n-i+p[ai[i]]+1); } if(i>p[ai[i]]) { tree_add(1,1,p[ai[i]],1,i-p[ai[i]]-1); tree_add(1,p[ai[i]]+1,p[ai[i]]+n-i+1,-1,n-i+p[ai[i]]+1); if(i-p[ai[i]]>1) tree_add(1,p[ai[i]]+n-i+2,n,1,i-n-p[ai[i]]-1); } if(i==p[ai[i]]) { tree_add(1,1,i,1,-1); if(i!=n) tree_add(1,i+1,n,-1,n+1); } } for(int i=1;i<=n;i++) X=INF,tree_query(1,i),printf("%d ",X); return 0; }