【问题描述】
有一颗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]
//以上u,v都只是对于某个点的代称,而非具体的点
问题在于如何快速求出这四个变量
对于LCA(u, v)是f的询问全部求出,然后再求LCA(u, v)是f的父亲的询问
这也就是说,实际上我们在计算lca是,先预处理一下,我们假设某个节点,他和某个点的lca可能是他的所有祖先,我们先拿他所有祖先的值来更新对于这个点的四个值,也就是我们暂时不管u和v的lca,而是对每一个点的每一种可能的情况分别进行处理
最后我们将这个节点和他的最远的祖先建立起一条链
然后在我们对每一组询问求解时,我们可以首先分别再次更新两个节点的所有父亲直到他们的公共祖先,
然后我们取值,求得答案即可
这样当我们求LCA(u,v)是f的父亲的询问的时候就可以借用已经求出的LCA(u,v)是f的询问
的结果,这样就不用反复去求u->f的那四个变量值,u->father[f]也能快速求出
这个变化主要在寻找father[v]这个过程中进行,具体看代码
需要注意的是,我们要更新f点的值,必须要知道u点的值,所以若u点还没被求过lca,即u点还未被访问,则直接continue
然后单独写博客的原因是:
邻接表空间开小!!!又是sb错误!!ac变成暴力分!!
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) { 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; 78 } 79 for(int i = lint[x]; i; i = et[i].net) { 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 << '\n'; 111 else cout << ans[i] << '\n'; 112 } 113 fclose(stdin); 114 fclose(stdout); 115 return 0; 116 }