1. 程式人生 > >【NOIP2013】 火柴排隊 貪心+splay

【NOIP2013】 火柴排隊 貪心+splay

ostream oid 操作 hup ins long set void pla

這題為啥我寫得這麽復雜。

首先我們不難發現,我們將序列$a$和序列$b$排序,考慮兩序列內無相同元素,那麽最小值顯然為$\sum_{i=1}^{n} (a_i-b_i)^2$。

下面考慮做法

首先,我們將序列$a$和序列$b$離散化(以下提及序列$a$和$b$均為離散化後的數字)

然後,我們從前往後枚舉序列$a$中的每一個數字,對於序列$a$中第$i$個數字$a_i$,我們在序列$b$中找出數字$a_i$的出現位置,並把它移動到序列$b$中第$i$個位置,與$a_i$對齊。

對於序列$b$,我們用一個$splay$來維護,其中會出現插入和刪除操作。

時間復雜度:$O(n log n)$。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<set>
 7 #include<map>
 8 #include<queue>
 9 #include<vector>
10 #define M 100005
11 #define L long long
12 #define MOD 99999997
13
#define lc(x) ch[x][0] 14 #define rc(x) ch[x][1] 15 using namespace std; 16 17 L ans=0,n,a[M]={0},b[M]={0},c[M]={0},wei[M]={0}; 18 L ch[M][2]={0},siz[M]={0},fa[M]={0},root=0; 19 20 void pushup(L x){siz[x]=siz[lc(x)]+siz[rc(x)]+1;} 21 void rotate(L x,L &k){ 22 L y=fa[x],z=fa[y]; 23 if(y==k) k=x;
24 else{ 25 if(lc(z)==y) lc(z)=x; 26 else rc(z)=x; 27 } 28 L l=(lc(y)!=x),r=l^1; 29 fa[y]=x; fa[x]=z; fa[ch[x][r]]=y; 30 ch[y][l]=ch[x][r]; ch[x][r]=y; 31 pushup(y); 32 pushup(x); 33 } 34 void splay(L x,L &k){ 35 while(x!=k){ 36 L y=fa[x],z=fa[y]; 37 if(y!=k){ 38 if((lc(z)==y)^(lc(y)==x)) rotate(x,k); 39 else rotate(y,k); 40 } 41 rotate(x,k); 42 } 43 } 44 45 void ins(L &x,L k,L id){ 46 if(!x) return void(x=id); 47 if(k<=siz[lc(x)]) ins(lc(x),k,id),fa[lc(x)]=x; 48 else ins(rc(x),k-siz[lc(x)]-1,id),fa[rc(x)]=x; 49 pushup(x); 50 } 51 void del(L id){ 52 splay(id,root); 53 L x=lc(id),y=rc(id); 54 siz[id]=1; fa[x]=fa[y]=0; 55 lc(id)=rc(id)=0; 56 if(!x) return void(root=y); 57 if(!y) return void(root=x); 58 root=x; 59 while(rc(x)) x=rc(x); 60 rc(x)=y; fa[y]=x; 61 splay(x,root); 62 } 63 64 signed main(){ 65 scanf("%d",&n); 66 for(L i=1;i<=n;i++) scanf("%lld",a+i),c[i]=a[i]; 67 sort(c+1,c+n+1); 68 for(L i=1;i<=n;i++) a[i]=lower_bound(c+1,c+n+1,a[i])-c; 69 for(L i=1;i<=n;i++) scanf("%lld",b+i),c[i]=b[i]; 70 sort(c+1,c+n+1); 71 for(L i=1;i<=n;i++) b[i]=lower_bound(c+1,c+n+1,b[i])-c; 72 for(L i=1;i<=n;i++) wei[b[i]]=i; 73 74 for(L i=1;i<=n;i++){ 75 siz[i]=1; 76 ins(root,i-1,i); 77 splay(i,root); 78 } 79 for(L i=1;i<=n;i++){ 80 int x=wei[a[i]]; 81 splay(x,root); 82 L nowid=siz[lc(x)]+1; 83 del(x); 84 ins(root,i-1,x); 85 splay(x,root); 86 ans+=abs(i-nowid); 87 } 88 cout<<ans%MOD<<endl; 89 }

【NOIP2013】 火柴排隊 貪心+splay