【平衡树】★平衡树 by onion_cyc
【莫队算法】
问题:给定长度为n的序列和m个区间询问,支持快速增减相邻元素维护区间信息。
将询问按左端点分块,块大小为$Q=\frac{n}{\sqrt m}$,块内按右端点排序。
然后依次回答询问,需要O(1)从(l,r)转移到(l,r+1),(l,r-1),(l-1,r),(l+1,r)。
复杂度分析:
左端点的移动,每个询问至多移动Q次,复杂度O(mQ)。
右端点的移动,每个块内至多移动n次,复杂度O(n*n/Q)。
平衡之后可以得到最佳块大小,复杂度$O(n\sqrt m)$。
【堆】
二叉堆
#include<cstdio> #include<algorithm> using namespace std; const int maxn=20010; int n,heap[maxn],sz; void heap_push(int x) { heap[++sz]=x;//新数入堆底 int now=sz;//以堆底为起点 while(now>1&&heap[now]<heap[now>>1])//非根节点的父亲>儿子时------注意非根判断 { swap(heap[now],heap[now>>1]);//交换即上推 now>>=1;//转移到父亲 } } int heap_pop() { int ans=heap[1];//取出答案 heap[1]=heap[sz--];//将堆底最后一个元素调上来 int now=1;//以堆顶为起点 while(now<=(sz>>1))//若now有儿子------儿子存在判断 { int next=now<<1;//令next为now的左儿子------儿子赋变量 if(next<sz&&heap[next]>heap[next|1])next++;//now有右儿子且右儿子更小时,令next为右儿子------左右儿子判断---注意右儿子存在判断 if(heap[next]>heap[now])return ans;//若根比儿子小,满足条件,退出 else { swap(heap[now],heap[next]);//交换即下推 now=next;//转移到儿子 } } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int u; scanf("%d",&u); heap_push(u); } long long ans=0; for(int i=1;i<n;i++) { int u=heap_pop(),v=heap_pop(); heap_push(u+v); ans+=u+v; } printf("%lld",ans); return 0; }