zoukankan      html  css  js  c++  java
  • 集训day15 t1 poj3728

    【问题描述】

    有一颗n个节点的树

    每个节点上都有许多奸商在卖东西,第i个奸商的理想价格为vi,即他会以vi的价格购买或卖出一件东西

    有m个人希望从树上的某个点走到另一个点,问你在只进行一次买卖(每次仅限一个商品)的情况下,每个人最多能赚多少钱

    【输入】

    输入第一行是一个整数 n,表示树上的点数。

    接下来n个正整数,表示每个奸商的理想价格。

    接下来n-1行,每行两个整数x,y,表示第x点和第y点有一条边。

    接下来一个整数m,表示下来有m个询问。

    接下来有m行,每行两个整数x和y,表示某个人要从第x点出发到第y点。

    【输出】

    输出包括m行。

    每行对应一个询问,一个整数,表示此人最多能赚到多少钱。

    【输入输出样例1】

    10

    3 4 1 2 7 6 1 5 3 9

    1 2

    1 9

    3 1

    9 7

    5 9

    6 9

    8 7

    4 7

    10 7

    3

    5 6

    8 10

    2 4

    3

    8

    1

    【数据范围】

    对于前40%数据 n<=1000, m<=1000

    对于100%数据 n<=250000 ,m<=10000

     

    t1
    离线lca+dp思想

     

    先说一说题外话,我后来看我自己的代码时,我看了差不多半天,也没有看懂。

    最后总算是理解了代码的思想。


    我们假设一个中间节点z
    一件商品,假设u和v的lca是z
    那么对于一次买卖,有三种情况:
    一件商品,我们在u,f之间买卖了,在u,f之间买了,在f,v之间卖了,在f,v之间买卖了
    接着我们想,对于三种情况,基于贪心的思想,必然是这样几种情况:
    1.在u,f间价格最小的地方买入,在u,f间价格最大的地方卖出,
    2.在u,f间价格最小的地方买入,在f,v间价格最大的地方卖出
    3.在f,v间价格最小的地方买入,在f,v间价格最大的地方卖出
    也就是说,我们要维护4个量:
    u,f间的最大和最小值,f,v间的最大和最小值
    从u到f 我们称为up, 从f到v我们称为down,而从u到f买然后在f到v卖就是求u到f的最小值和f到v的最大值


    先求出u,v的最近公共祖先f
    再求出u到f再到v的最大利润值maxval
    这个maxval有三种情况
    1.可能是u到f的利润最大值
    2.可能是f到v的利润最大值
    3.可能是f到v的最大w[i] - u到f的最小w[i]
    这样就是说,我们需要4个变量才能得到最终的利润最大值
    up[u]表示u到f的利润最大值
    down[v]表示f到v的利润最大值
    maxw[u]表示u到f的最大w[i]
    minw[u]表示u到f的最小w[i]

    首先,我们可以知道的是,原来我们暴力写肯定就是先求出LCA,然后再从u和v到lca更新重新更新

    所以我们的优化思路是在求LCA的同时对4个值进行更新

    那么我接下来就要解决这个问题了,我们显然可以用到一些DP的思想,

    我们上面已经开了4个数组

    up[u]表示u到f的利润最大值
    down[v]表示f到v的利润最大值
    maxw[u]表示u到f的最大w[i]
    minw[u]表示u到f的最小w[i]

    然后我们在利用并查集路径压缩的同时更新这些值,现在我们要解决的是,如何能按照求lca的次序,同时回答询问

    这就是说我们要给询问排一个序号,按照求lca得顺序完成询问,然后通过序号,把答案确定在答案数组的正确位置。

    对于每个点, 我们进行dfs的时候,查看与其相关的询问,

    假设当前点是u, 询问的点是v, u和v的LCA是f,如果v已经dfs过了,说明v在并查集中的祖先就是u,v的LCA  f点, 

    将该询问加入到f的相关集合中,等f所有的子节点都处理过后再去处理f, 就可以发现,一切都是顺其自然了

    在这些处理过程中,up和down以及u,v到f的最大值最小值  都可以在并查集求压缩路径的过程中更新。

    同时我们注意到,

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int maxn = 250086;
      4 const int maxm = 10086;
      5 struct kkk {
      6     int net, y, id;
      7 }ef[maxn << 1], es[maxn << 1], et[maxn << 1];
      8 int linf[maxn], lenf = 0;
      9 int lins[maxn], lens = 0;
     10 int lint[maxn], lent = 0;
     11 int n, m, w[maxn];
     12 int fa[maxn], u[maxm], v[maxm];
     13 int up[maxn], down[maxn];
     14 int maxw[maxn], minw[maxn];
     15 int ans[maxn];
     16 int vis[maxn];
     17 
     18 inline int read() {
     19     int x = 0, y = 1;
     20     char ch = getchar();
     21     while(!isdigit(ch)) {
     22         if(ch == '-') y = -1;
     23         ch = getchar();
     24     }
     25     while(isdigit(ch)) {
     26         x = (x << 1) + (x << 3) + ch - '0';
     27         ch = getchar();
     28     }
     29     return x * y;
     30 }
     31 
     32 inline void insert_f(int xx, int yy, int id) {
     33     ef[++lenf].net = linf[xx];
     34     ef[lenf].id = id;
     35     ef[lenf].y = yy;
     36     linf[xx] = lenf;
     37 }
     38 
     39 inline void insert_s(int xx, int yy, int id) {
     40     es[++lens].id = id;
     41     es[lens].net = lins[xx];
     42     es[lens].y = yy;
     43     lins[xx] = lens;
     44 }
     45 
     46 inline void insert_t(int xx, int yy, int id) {
     47     et[++lent].id = id;
     48     et[lent].net = lint[xx];
     49     et[lent].y = yy;
     50     lint[xx] = lent;
     51 }
     52 
     53 inline int getfather(int x) {
     54     if(x == fa[x]) return x;
     55     int f = fa[x];
     56     fa[x] = getfather(fa[x]);
     57     up[x] = max(max(up[x], up[f]), maxw[f] - minw[x]);
     58     down[x] = max(max(down[x], down[f]), maxw[x] - minw[f]);
     59     maxw[x] = max(maxw[x], maxw[f]);
     60     minw[x] = min(minw[x], minw[f]);
     61     return fa[x];
     62 }
     63 
     64 inline void LCA(int x) {//x表示的是公共祖先 
     65     vis[x] = 1;
     66     fa[x] = x;
     67     for(int i = lins[x]; i; i = es[i].net) {
     68         int to = es[i].y, id = es[i].id;
     69         if(!vis[to]) continue;
     70         int dad = getfather(to);
     71         insert_t(dad, x, id); 
     72     }
     73     for(int i = linf[x]; i; i = ef[i].net) {
     74         int to = ef[i].y;
     75         if(vis[to]) continue;
     76         LCA(to);
     77         fa[to] = x;//把to的父亲标记为他的父亲 
     78     }
     79     for(int i = lint[x]; i; i = et[i].net) {//在父亲节点x处理所有的关于他的子节点的询问
     80         int id = et[i].id;
     81         getfather(u[id]);
     82         getfather(v[id]);
     83         ans[id] = max(max(up[u[id]], down[v[id]]), maxw[v[id]] - minw[u[id]]);
     84     }
     85 }
     86 
     87 int main() {
     88 //    freopen("gift.in", "r", stdin);
     89 //    freopen("gift.out", "w", stdout);
     90     n = read();
     91     for(int i = 1; i <= n; ++i) {
     92         w[i] = read();
     93         up[i] = down[i] = 0;
     94         maxw[i] = minw[i] = w[i];
     95     }
     96     for(int i = 1; i < n; ++i) {
     97         int x, y;
     98         x = read(), y = read();
     99         insert_f(x, y, i);
    100         insert_f(y, x, i);
    101     }
    102     m = read();
    103     for(int i = 1; i <= m; ++i) {
    104         u[i] = read(), v[i] = read();
    105         insert_s(u[i], v[i], i);
    106         insert_s(v[i], u[i], i);
    107     }
    108     LCA(1);
    109     for(int i = 1; i <= m; ++i) {
    110         if(ans[i] < 0) cout << 0 << '
    ';
    111         else cout << ans[i] << '
    ';
    112     }
    113 //    fclose(stdin);
    114 //    fclose(stdout);
    115     return 0;
    116 }

     但是此代码并不能A掉Poj原题,因为,数据范围不一样

  • 相关阅读:
    数据库与数据仓库的区别
    MySQL数据库与表的最基本命令大盘点
    SQL Server 2008创建数据库
    [HttpClient]简单使用GET请求
    [HttpClient]HttpClient简介
    [jQuery编程挑战]003 克隆一个页面元素及其相关事件
    [设计模式]观察者模式
    [jQuery编程挑战]002:实现一个转盘大抽奖
    [设计模式]备忘录模式
    [javascript]String添加trim和reverse方法
  • 原文地址:https://www.cnblogs.com/ywjblog/p/9335560.html
Copyright © 2011-2022 走看看