bzoj1455: 罗马游戏 + bzoj2809: Dispatching(可并堆)

昨天看了可并堆是什么,写的是左偏树

大概就是一棵树

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 }
View Code

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 }
View Code
原文地址:https://www.cnblogs.com/mzl0707/p/6072328.html