• 【贪心 计数 倍增】bzoj4458: GTY的OJ


    倍增写挂调了半个晚上

    Description

    身为IOI金牌的gtyzs有自己的一个OJ,名曰GOJ。GOJ上的题目可谓是高质量而又经典,他在他的OJ里面定义了一个树形的分类目录,且两个相同级别的目录是不会重叠的。比如图论的大目录下可能分为最短路,最小生成树,网络流等低一级的分类目录,这些目录下可能还有更低一级的目录,以此类推。现在gtyzs接到了一个任务,要他为SDTSC出题。他准备在自己的OJ题库中找出M道题作为SDTSC的试题,而他深知SDTSC的童鞋们个个都是神犇,所以gtyzs认为自己出的这M道题中,每道题都应该属于不少于L种分类目录;可他又怕自己的题没有人会做,所以每道题也应该属于不超过R种分类目录,并且这些分类目录应该是连续的,不能出现断层。对了,最重要的是,不存在一道题,它属于两个分类目录且这两个目录不是包含关系。(比如不存在一道题它既是一道DP题,又是一道网络流题)gtyzs怕被骂,所以他希望不存在任意的一对题目(u,v),使得u所属的分类目录与v完全相同。举例来说,gtyzs不能出两道同样的都是动态规划,背包的题,但是却可以出一道属于动态规划,背包和01背包的题和一道属于背包,01背包的题,当然也可以出一个属于图论的题和一个属于数论的题。(注意:一道题所属的分类目录不一定从根开始,如加粗部分所示)
    为了让自己的题目变得更加靠谱,他给每一个分类目录都定了一个靠谱值ai,这个值可正可负。一道题的靠谱度为其从属的分类目录靠谱值的加和。我们假设动态规划的靠谱值为10,插头DP的靠谱值为-5,则一道动态规划插头DP的题的靠谱值就是5。gtyzs希望自己出的这M道题,在满足上述前提条件下,靠谱度总和最大。gtyzs当然会做啦,于是你就看到了这个题。

    Input

    输入的第一行是一个正整数N,代表分类目录的总数。
    接下来的一行,共N个正整数,第i个正整数为fi,表示分类目录i被fi所包含。保证一个分类目录只会被一个分类目录所包含,且包含关系不存在环。特别的,fi=0表示它是根节点,我们保证这样的点只存在一个。
    接下来的一行,共N个整数,第i个数表示ai。
    最后一行,三个正整数M,L,R。
    对于100%的数据,1≤N≤500,000,1≤M≤500,000,|ai|≤2,000。保证输入数据有解。
    为了方便,所有的测试数据中都有f1=0,且对于任意的i∈[2,N],有fi<i。

    Output

    一行一个整数,表示最大的靠谱度。

    Sample Input

    7
    0 1 1 2 2 3 3
    2 3 4 1 2 3 4
    3 3 3

    Sample Output

    26

    题目分析

    树上超级钢琴,配合bzoj2006: [NOI2010]超级钢琴食用更佳。

    思路几乎一模一样,不过是应用了一些树与序列不同的性质去做这个事情:前缀和上树;倍增维护点$u$至$2^i$个祖先上路径$sum_i$最小值。有些±1的细节可能需要好好注意。

    倍增还不够熟练

      1 #include<bits/stdc++.h>
      2 typedef long long ll;
      3 typedef std::pair<ll, int> pr;
      4 const int maxn = 500035;
      5 const int maxm = 500035;
      6 
      7 ll ans;
      8 pr st[maxn][23];
      9 int fa[maxn][23],dep[maxn];
     10 int n,m,L,R,w[maxn],s[maxn];
     11 int edgeTot,head[maxn],nxt[maxm],edges[maxm];
     12 struct node
     13 {
     14     int u,l,r,p;
     15     ll w;
     16     pr query(int x, int d)
     17     {
     18         pr ret = pr(s[x],x);
     19         for (int i=20; i>=0; i--)
     20             if ((d>>i)&1) ret = std::min(ret, st[x][i]), x = fa[x][i];
     21         return ret;
     22     }
     23     int findFa(int x, int d)
     24     {
     25         for (int i=20; i>=0; i--)
     26             if ((d>>i)&1) x = fa[x][i];
     27         return x;
     28     }
     29     void calc()
     30     {
     31         int fa = findFa(u, l);
     32         pr tmp = query(fa, r-l);
     33         w = s[u]-tmp.first;
     34         p = dep[u]-dep[tmp.second];
     35         
     36     }
     37     node(int a, int b, int c):u(a),l(b),r(c) {}
     38     bool operator < (node a) const
     39     {
     40         return w < a.w;
     41     }
     42 };
     43 std::priority_queue<node> q;
     44 
     45 int read()
     46 {
     47     char ch = getchar();
     48     int num = 0;
     49     bool fl = 0;
     50     for (; !isdigit(ch); ch=getchar())
     51         if (ch=='-') fl = 1;
     52     for (; isdigit(ch); ch=getchar())
     53         num = (num<<1)+(num<<3)+ch-48;
     54     if (fl) num = -num;
     55     return num;
     56 }
     57 void addedge(int u, int v)
     58 {
     59     if (!u) return;
     60     fa[v][0] = u, edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
     61 }
     62 void init()
     63 {
     64     for (int i=1; i<=n; i++)
     65         s[i] += s[fa[i][0]]+w[i], dep[i] = dep[fa[i][0]]+1;
     66     for (int j=1; j<=20; j++)
     67         for (int i=1; i<=n; i++)
     68             fa[i][j] = fa[fa[i][j-1]][j-1];
     69     for (int i=0; i<=n; i++) st[i][0] = pr(s[fa[i][0]], fa[i][0]);
     70     for (int j=1; j<=20; j++)
     71         for (int i=0; i<=n; i++)
     72             st[i][j] = std::min(st[i][j-1], st[fa[i][j-1]][j-1]);
     73 }
     74 int main()
     75 {
     76     memset(head, -1, sizeof head);
     77     n = read();
     78     for (int i=1; i<=n; i++) addedge(read(), i);
     79     for (int i=1; i<=n; i++) w[i] = read();
     80     m = read(), L = read(), R = read();
     81     init();
     82     for (int i=1; i<=n; i++)
     83     {
     84         if (dep[i] < L) continue;
     85         int l = L, r = std::min(dep[i], R);
     86         if (l <= r){
     87             node tmp = node(i, l, r);
     88             tmp.calc(), q.push(tmp); 
     89         }
     90     }
     91     while (m--)
     92     {
     93         if (q.empty()) break;
     94         node tt = q.top();
     95         q.pop(), ans += tt.w;
     96         int u = tt.u, l = tt.l, r = tt.r, p = tt.p;
     97         if (l < p){
     98             node tmp = node(u, l, p-1);
     99             tmp.calc(), q.push(tmp);
    100         }
    101         if (r > p){
    102             node tmp = node(u, p+1, r);
    103             tmp.calc(), q.push(tmp);
    104         }
    105     }
    106     printf("%lld
    ",ans);
    107     return 0;
    108 }

    END

  • 相关阅读:
    【收藏】如何理解二维数组
    【algo&ds】9.拓扑排序、AOV&AOE、关键路径问题
    【algo&ds】8.最小生成树
    【algo&ds】7.最短路径问题
    【algo&ds】6.图及其存储结构、遍历
    【c&c++】变量初始化
    【algo&ds】【pat】5.并查集及其应用
    【algo&ds】4.B树、字典树、红黑树、跳表
    【algo&ds】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、散列表
    【algo&ds】3.栈和队列
  • 原文地址:https://www.cnblogs.com/antiquality/p/9874683.html
Copyright © 2020-2023  润新知