昨天看了可并堆是什么,写的是左偏树
大概就是一棵树
1、有左偏性质,即当前根到左叶子节点距离比到右叶子节点距离大
2、有堆性质,堆顶关键字比子树关键字小
合并两个堆的时候,关键字大的插入到关键字小的那堆的右子树中,右子树的深度大于左子树时交换两者以维持左偏性质。
堆中个数太多的时候,pop堆顶的元素x
具体是合并左右两个子树后返回新的堆顶元素y,清除完x的信息后root[x]指向y
bzoj1455:用并查集合并团,用可并堆维护团中最小的人。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 1000010; 6 int n,m,v[maxn],vis[maxn],fa[maxn],l[maxn],r[maxn],a,b,d[maxn]; 7 char s[3]; 8 9 int find(int x){ 10 return (fa[x]==x)?x:fa[x]=find(fa[x]); 11 } 12 13 int merge(int x, int y){ 14 if (!x || !y) return x+y; 15 if (v[x]>v[y]) swap(x,y); //保证堆顶最小 16 r[x]=merge(r[x],y); 17 if (d[r[x]]>d[l[x]]) swap(l[x],r[x]); 18 d[x]=d[r[x]]+1; 19 return x; 20 } 21 22 int main(){ 23 scanf("%d", &n); 24 for (int i=1; i<=n; i++) scanf("%d", &v[i]); 25 scanf("%d", &m); d[0]=-1; 26 for (int i=1; i<=n; i++) fa[i]=i; 27 for (int i=1; i<=m; i++){ 28 scanf("%s", s); 29 if (s[0]=='M'){ 30 scanf("%d%d", &a, &b); 31 if (vis[a] || vis[b]) continue; 32 int fx=find(a), fy=find(b); 33 if (fx!=fy) fa[fx]=fa[fy]=merge(fx,fy); // 合并从堆顶开始合并 34 }else{ 35 scanf("%d", &a); 36 if (vis[a]) puts("0"); 37 else{ 38 int fx=find(a); vis[fx]=1;// printf(" %d ", fx); 39 printf("%d ", v[fx]); 40 fa[fx]=merge(l[fx],r[fx]); 41 fa[fa[fx]]=fa[fx]; 42 } 43 } 44 } 45 return 0; 46 }
bzoj2809:DFS一遍,从叶子节点开始向上递归,到一个节点,可并堆维护当前子树中满足预算的最多人数,然后用当前子树更新答案。具体是每个节点都插入,超出预算就pop最大花费的人直到满足预算
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define LL long long 5 using namespace std; 6 const int maxn = 100010; 7 struct node{ 8 int to,next; 9 }e[maxn]; 10 struct heap{ 11 int l,r; 12 LL val; 13 }t[maxn]; 14 int n,m,root[maxn],tot=1,head[maxn]; 15 LL v[maxn],w[maxn],ans,sum[maxn],add[maxn]; 16 17 void insert(int u, int v){ 18 e[++tot].to=v; e[tot].next=head[u]; head[u]=tot; 19 } 20 21 int merge(int x, int y){ 22 if (!x || !y) return x+y; 23 if (t[x].val<t[y].val) swap(x,y); 24 t[x].l=merge(t[x].l,y); 25 swap(t[x].l,t[x].r); 26 return x; 27 } 28 29 void Pop(int x){ 30 int rt=root[x]; 31 root[x]=merge(t[rt].l,t[rt].r); 32 sum[x]--; add[x]-=t[rt].val; 33 t[rt].l=t[rt].r=t[rt].val=0; 34 } 35 36 void dfs(int u){ 37 add[u]=sum[u]=0; 38 for (int i=head[u],vv; i; i=e[i].next){ 39 dfs(vv=e[i].to); 40 add[u]+=add[vv]; sum[u]+=sum[vv]; 41 root[u]=merge(root[u],root[vv]); 42 while (add[u]>m) Pop(u); 43 } 44 add[u]+=v[u]; sum[u]++; 45 t[u]=(heap){0,0,v[u]}; 46 root[u]=merge(root[u],u); 47 while (add[u]>m) Pop(u); 48 ans=max(ans,sum[u]*w[u]); 49 } 50 51 int main(){ 52 scanf("%d%d", &n, &m); int s; 53 for (int i=1; i<=n; i++){ 54 int x; 55 scanf("%d%lld%lld", &x, &v[i], &w[i]); 56 insert(x,i); if (!x) s=i; 57 } 58 dfs(s); 59 printf("%lld ", ans); 60 return 0; 61 }