zoukankan      html  css  js  c++  java
  • [APIO2012]派遣

    嘟嘟嘟

    人生A了的第一道左偏树题。

    题面太长了,概括一下:给定一棵 n 个点的有根树,每个点有两个属性 Ci 与 Li,现在你要指定一个点 R,并在 R的子树内选取若干点(可以选取 R 自己),使得这些点的 Ci 的和不超过 M,而一个选取方案的价值为选取人数 * LR,求选取方案的最大价值。

    假设现在已经确定了R,那么我们应该在R的子树内部选取尽量多的点,又因为每一个点对答案的贡献是一样的,所以应该选Ci 尽量小的点,那么对于树中的每一个节点,维护一个大根堆,如果这个堆的sum > m,就删除堆顶元素,直到sum < m。一个节点的堆可以有他的子节点的堆合并而来,所以这个堆不仅要支持删除,还要支持合并,那么就用左偏树吧。

    总结一下:每一个节点维护一个左偏树,左偏树中还要维护节点个数和ΣCi,然后自底往上合并堆,并用这个节点的答案更新答案。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 1e5 + 5;
    21 inline ll read()
    22 {
    23   ll ans = 0;
    24   char ch = getchar(), last = ' ';
    25   while(!isdigit(ch)) {last = ch; ch = getchar();}
    26   while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27   if(last == '-') ans = -ans;
    28   return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32   if(x < 0) x = -x, putchar('-');
    33   if(x >= 10) write(x / 10);
    34   putchar(x % 10 + '0');
    35 }
    36 
    37 int n;
    38 ll m;
    39 int c[maxn], l[maxn];
    40 struct Edge
    41 {
    42   int nxt, to;
    43 }e[maxn];
    44 int head[maxn], ecnt = 0;
    45 void addEdge(int x, int y)
    46 {
    47   e[++ecnt] = (Edge){head[x], y};
    48   head[x] = ecnt;
    49 }
    50 
    51 int root[maxn], ls[maxn], rs[maxn], dis[maxn], v[maxn];     //大根堆
    52 ll sum[maxn], ans = 0;
    53 int siz[maxn];
    54 
    55 int merge(int x, int y)
    56 {
    57   if(!x || !y) return x | y;
    58   if(v[x] < v[y]) swap(x, y);
    59   rs[x] = merge(rs[x], y);
    60   if(dis[ls[x]] < dis[rs[x]]) swap(ls[x], rs[x]);
    61   dis[x] = dis[rs[x]] + 1;
    62   siz[x] = siz[ls[x]] + siz[rs[x]] + 1;  //跟线段树有点像,这个节点的信息从子节点更新而来
    63   sum[x] = sum[ls[x]] + sum[rs[x]] + v[x];
    64   return x;
    65 }
    66 int Del(int x)
    67 {
    68   return merge(ls[x], rs[x]);
    69 }
    70 
    71 void newNode(int now)
    72 {
    73   sum[now] = v[now] = c[now];
    74   siz[now] = 1; root[now] = now;
    75 }
    76 void dfs(int now)
    77 {
    78   newNode(now);
    79   for(int i = head[now]; i; i = e[i].nxt)
    80     {
    81       dfs(e[i].to);
    82       root[now] = merge(root[now], root[e[i].to]);
    83     }
    84   while(sum[root[now]] > m && siz[root[now]]) root[now] = Del(root[now]);
    85   ans = max(ans, (ll)siz[root[now]] * (ll)l[now]); //别忘加ll
    86 }
    87 
    88 int main()
    89 {
    90   n = read(); m = read();
    91   for(int i = 1; i <= n; ++i)
    92     {
    93       int x = read(); c[i] = read(); l[i] = read();
    94       if(x) addEdge(x, i);
    95     }
    96   dfs(1);
    97   write(ans); enter;
    98   return 0;
    99 }
    View Code
  • 相关阅读:
    Fileupload文件上传下载
    携程运维自动化平台,上万服务器变更也可以很轻松
    判断某个日期是不是该月的第一天或最后一天
    js format 设置日期格式 将Fri Dec 12 2014 08:00:00 GMT+0800改为2014-12-12 8:00:00
    js13位时间戳转换,10位时间戳转换
    java io包File类
    为什么前端实现的页面跟设计师的设计稿的差别那么大?
    为什么前端实现的页面跟设计师的设计稿的差别那么大?
    为什么前端实现的页面跟设计师的设计稿的差别那么大?
    为什么前端实现的页面跟设计师的设计稿的差别那么大?
  • 原文地址:https://www.cnblogs.com/mrclr/p/9799191.html
Copyright © 2011-2022 走看看