P3521 [POI2011]ROT-Tree Rotations
P3521 [POI2011]ROT-Tree Rotations
本题可以通过合并数据结构解决。
权值线段树合并的时间复杂度为O(nlogn)。
证明:
• n个节点相互独立。
• 考虑合并节点的意义:两棵线段树在当前区间内都有值且新的树在当前区间的值相对原来两棵树的值都增加了。
• 说明对于一个线段树区间,merge时访问到它的次数不会超过该区间的长度大小次。
• 那么显然总访问次数的上限为 nlogn。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int n,root,now,cnt; 5 ll a,b,ans; 6 int sum[4000050]; 7 int son[4000050][2]; 8 void calc_add(int &u,int l,int r) 9 { 10 u=++cnt; ++sum[u]; 11 if(l==r) return ; 12 int mid=(l+r)>>1; 13 if(now<=mid) calc_add(son[u][0],l,mid); 14 else calc_add(son[u][1],mid+1,r); 15 } 16 void merge(int &u,int v) 17 { 18 if(!u||!v) 19 { 20 u=u|v; 21 return ; 22 } 23 sum[u]+=sum[v]; 24 a+=(ll)sum[son[u][0]]*sum[son[v][1]]; 25 b+=(ll)sum[son[u][1]]*sum[son[v][0]]; 26 merge(son[u][0],son[v][0]); 27 merge(son[u][1],son[v][1]); 28 } 29 void dfs(int &u) 30 { 31 scanf("%d",&now); 32 int ls,rs; 33 if(!now) 34 { 35 dfs(ls=0); dfs(rs=0); 36 a=b=0; u=ls; 37 merge(u,rs); 38 ans+=min(a,b); 39 } 40 else 41 calc_add(u,1,n); 42 } 43 int main() 44 { 45 scanf("%d",&n); 46 dfs(root); 47 printf("%lld",ans); 48 return 0; 49 }