• 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
  • 相关阅读:
    POJ 2104 K-th Number(主席树模板题)
    HDU 6072 Logical Chain(Kosaraju+bitset)
    POJ 2728 Desert King(最优比率生成树 01分数规划)
    HDU 6150 Vertex Cover(构造)
    51nod 1693 水群(神奇的最短路!)
    51nod 1444 破坏道路(最短路)
    51nod 1076 2条不相交的路径(边双连通分量)
    HDU 6156 Palindrome Function
    Cortex-M0(+)内核的处理器架构简介
    [转] 软件开发流程
  • 原文地址:https://www.cnblogs.com/mzl0707/p/6072328.html
Copyright © 2020-2023  润新知