[O]の値は、問題の解決策を見つけるために[CH1301]
ポータル:Oの値下さい\([CH1301]を\) \([AcWing136] \)
説明[タイトル]
長さを考えると(N- \)\シーケンス\(A \)、\ (A \)の数字は変動します。
\(\ FORALL iがで\ [ 2、N] \) を探している\(_ {J = 1分 } ^ {J <I} | a_iを-A_j | \) 最小値取得時の\を(J \) 。最小点が一意でない場合は、選択し\(A_j \)小さい方の値を。
[サンプル]
样例输入:
3
1 5 3
样例输出:
4 1
2 1
[データ範囲]
\(100 \%の\) \(nはleqslant \ 10「5 |愛| \ leqslant 10 ^ 9 \)
[分析]
リストの正のソリューション。私は、セグメントツリー書くことができこんにゃくのこのリストは好きではありません\(QAQ \を)。
第1の離散し、維持量ツリー線、第\([1] \)を加えました。
それぞれの後ろについて\(私は\)前で、最初のクエリがより多くを持っているその小さな、に設定\(レベル\) 。
このとき、第1のシーケンス\(レベル\)多数である([I] \)\の前駆体、\(レベル+ 1 \)大きいです\([I] \)の後継(SEQ異なるの数)。
どちらの最小、選択された前駆体であれば同じです。
時間の複雑さ:\(O(nlogn)\) 。
セグメントツリー定数が比較的大きいので、少し遅いが、また、持っていたことができます。
【コード】
#include<algorithm>
#include<cstdio>
#include<map>
#define pl (p<<1)
#define pr (p<<1|1)
#define mid (L+R>>1)
#define Re register int
using namespace std;
const int N=1e5+3;
int x,y,z,n,k,t,cnt,asw,tmp,root,a[N],b[N];
struct QAQ{int g,l,r;}tr[N<<2];map<int,int>id;
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline void build(Re p,Re L,Re R){//初始化建树
tr[p].l=L,tr[p].r=R;
if(L==R)return;
build(pl,L,mid),build(pr,mid+1,R);
}
inline void add(Re p,Re x,Re l,Re r){//单点修改
Re L=tr[p].l,R=tr[p].r;
if(L==R){++tr[p].g;return;}
if(x<=mid)add(pl,x,l,r);
else add(pr,x,l,r);
tr[p].g=tr[pl].g+tr[pr].g;
}
inline int ask(Re p,Re k){//查询第k大
if(tr[p].l==tr[p].r)return tr[p].r;
if(tr[pl].g>=k)return ask(pl,k);
else return ask(pr,k-tr[pl].g);
}
inline int ask_level(Re p,Re x){//查询小于等于x的个数
Re L=tr[p].l,R=tr[p].r;
if(L==R)return tr[p].g;
if(x<=mid)return ask_level(pl,x);
else return tr[pl].g+ask_level(pr,x);
}
int main(){
in(n);
for(Re i=1;i<=n;++i){
in(a[i]);
if(!id[b[i]=a[i]])id[a[i]]=i;
}
sort(b+1,b+n+1),build(1,1,n);
add(1,lower_bound(b+1,b+n+1,a[1])-b,1,n);
for(Re i=2;i<=n;++i){
k=lower_bound(b+1,b+n+1,a[i])-b;
Re level=ask_level(1,k-1);//查询小于a[i]的个数
if(level)asw=ask(1,level);//查找第level大(即前驱后继)
if(level+1<=i-1){
tmp=ask(1,level+1);//查找第level+1大(即a[i]后继)
if(!asw||abs(a[i]-b[asw])>abs(b[tmp]-a[i]))asw=tmp;
//只有小于才赋值,等于时选择最小的a[j](即a[i]前驱)
}
printf("%d %d\n",abs(a[i]-b[asw]),id[b[asw]]);
add(1,k,1,n);
}
}