集训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的最大值最小值 都可以在并查集求压缩路径的过程中更新。
同时我们注意到,
#include<bits/stdc++.h>
using namespace std;
const int maxn = ;
const int maxm = ;
struct kkk {
int net, y, id;
}ef[maxn << ], es[maxn << ], et[maxn << ];
int linf[maxn], lenf = ;
int lins[maxn], lens = ;
int lint[maxn], lent = ;
int n, m, w[maxn];
int fa[maxn], u[maxm], v[maxm];
int up[maxn], down[maxn];
int maxw[maxn], minw[maxn];
int ans[maxn];
int vis[maxn]; inline int read() {
int x = , y = ;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') y = -;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << ) + (x << ) + ch - '';
ch = getchar();
}
return x * y;
} inline void insert_f(int xx, int yy, int id) {
ef[++lenf].net = linf[xx];
ef[lenf].id = id;
ef[lenf].y = yy;
linf[xx] = lenf;
} inline void insert_s(int xx, int yy, int id) {
es[++lens].id = id;
es[lens].net = lins[xx];
es[lens].y = yy;
lins[xx] = lens;
} inline void insert_t(int xx, int yy, int id) {
et[++lent].id = id;
et[lent].net = lint[xx];
et[lent].y = yy;
lint[xx] = lent;
} inline int getfather(int x) {
if(x == fa[x]) return x;
int f = fa[x];
fa[x] = getfather(fa[x]);
up[x] = max(max(up[x], up[f]), maxw[f] - minw[x]);
down[x] = max(max(down[x], down[f]), maxw[x] - minw[f]);
maxw[x] = max(maxw[x], maxw[f]);
minw[x] = min(minw[x], minw[f]);
return fa[x];
} inline void LCA(int x) {//x表示的是公共祖先
vis[x] = ;
fa[x] = x;
for(int i = lins[x]; i; i = es[i].net) {
int to = es[i].y, id = es[i].id;
if(!vis[to]) continue;
int dad = getfather(to);
insert_t(dad, x, id);
}
for(int i = linf[x]; i; i = ef[i].net) {
int to = ef[i].y;
if(vis[to]) continue;
LCA(to);
fa[to] = x;//把to的父亲标记为他的父亲
}
for(int i = lint[x]; i; i = et[i].net) {//在父亲节点x处理所有的关于他的子节点的询问
int id = et[i].id;
getfather(u[id]);
getfather(v[id]);
ans[id] = max(max(up[u[id]], down[v[id]]), maxw[v[id]] - minw[u[id]]);
}
} int main() {
// freopen("gift.in", "r", stdin);
// freopen("gift.out", "w", stdout);
n = read();
for(int i = ; i <= n; ++i) {
w[i] = read();
up[i] = down[i] = ;
maxw[i] = minw[i] = w[i];
}
for(int i = ; i < n; ++i) {
int x, y;
x = read(), y = read();
insert_f(x, y, i);
insert_f(y, x, i);
}
m = read();
for(int i = ; i <= m; ++i) {
u[i] = read(), v[i] = read();
insert_s(u[i], v[i], i);
insert_s(v[i], u[i], i);
}
LCA();
for(int i = ; i <= m; ++i) {
if(ans[i] < ) cout << << '\n';
else cout << ans[i] << '\n';
}
// fclose(stdin);
// fclose(stdout);
return ;
}
但是此代码并不能A掉Poj原题,因为,数据范围不一样
集训day15 t1 poj3728的更多相关文章
- FJ省队集训DAY3 T1
思路:我们考虑如果取掉一个部分,那么能影响到最优解的只有离它最近的那两个部分. 因此我们考虑堆维护最小的部分,离散化离散掉区间,然后用线段树维护区间有没有雪,最后用平衡树在线段的左右端点上面维护最小的 ...
- Yali7月集训Contest2 T1 Cube 题解
题目链接: 连我们都只有纸质题目...话说雅礼集训都是这样的吗... 大意 0维基本图形是一个点 1维基本图形是一条线段 2维基本图形是一个正方形 3维基本图形是一个正方体 4维基本图形是... 求\ ...
- FJ省队集训DAY5 T1
思路:考试的时候打了LCT,自以为能过,没想到只能过80.. 考完一想:lct的做法点数是100W,就算是nlogn也会T. 讲一下lct的做法把:首先如果一条边连接的两个点都在同一个联通块内,那么这 ...
- FJ省队集训DAY4 T1
直接上题解 #include<cstdio> #include<iostream> #include<cmath> #include<cstring> ...
- FJ省队集训DAY2 T1
思路:转换成n条三维空间的直线,求最大的集合使得两两有交点. 有两种情况:第一种是以某2条直线为平面,这时候只要统计这个平面上有几条斜率不同的直线就可以了 还有一种是全部交于同一点,这个也只要判断就可 ...
- FJ省队集训DAY1 T1
题意:有一堆兔子,还有一个r为半径的圆,要求找到最大集合满足这个集合里的兔子两两连边的直线不经过圆. 思路:发现如果有两个点之间连边不经过圆,那么他们到圆的切线会构成一段区间,那么这两个点的区间一定会 ...
- 雅礼集训 Day7 T1 Equation 解题报告
Reverse 题目背景 小\(\text{G}\)有一个长度为\(n\)的\(01\)串\(T\),其中只有\(T_S=1\),其余位置都是\(0\).现在小\(\text{G}\)可以进行若干次以 ...
- 雅礼集训 Day6 T1 Merchant 解题报告
Merchant 题目描述 有\(n\)个物品,第\(i\)个物品有两个属性\(k_i,b_i\),表示它在时刻\(x\)的价值为\(k_i\times x+b_i\). 当前处于时刻\(0\),你可 ...
- 雅礼集训 Day1 T1 养花
养花 题目描述 小\(C\)在家种了\(n\)盆花,每盆花有一个艳丽度\(a_i\). 在接下来的\(m\)天中,每天早晨他会从一段编号连续的花中选择一盆摆放在客厅, 并在晚上放回. 同时每天有特定的 ...
随机推荐
- 2017南开ACM校赛(网络赛) 民间题解
orz 首先说一下这个只是民间题解,可能会有很多错误 程序还没有评测,所以可能存在问题 C题比赛的时候没想到..后来发现是个模板题,所以没有代码 希望这份题解能对读者有所启发吧... A题 直接倒序枚 ...
- Lua学习笔记:面向对象
Lua学习笔记:面向对象 https://blog.csdn.net/liutianshx2012/article/details/41921077 Lua 中只存在表(Table)这么唯一一种数据结 ...
- bzoj4145 AMPPZ2014 The Prices 状压dp
这个题.......很可以,很小清晰......反正正经的东西我都没想到:重点在于——————我不会处理那个多出来的路费所以当时我就骚骚的弄了一颗树包状压其实这是一个类01背包的状压在每个状态用01背 ...
- poj1185 炮兵阵地 状压dp
司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示) ...
- PHP报错Cannot adopt OID in UCD-SNMP-MIB、 LM-SENSORS-MIB
Cannot adopt OID in UCD-SNMP-MIB: Cannot adopt OID in LM-SENSORS-MIB: lmTempSensorsValue 运行PHP遇到这些错误 ...
- SynchronizationContext.Post方法 代替
http://www.codeproject.com/KB/threads/SynchronizationContext.aspx看吧,不好,就将就的看下我的吧,呵呵!(没有直接翻译,不过大概的思路相 ...
- 慕课网javascript 进阶篇 第九章 编程练习
把平常撸的码来博客上再撸一遍既可以加深理解,又可以理清思维.还是很纯很纯的小白,各位看官老爷们,不要嫌弃.最近都是晚睡,昨晚也不例外,两点多睡的.故,八点起来的人不是很舒服,脑袋有点晕呼呼,鉴于昨晚看 ...
- Ubuntu pppoe 拨号上网
-------------蓝色是终端里面的连接方式,可以不看--------------------- ADSL上网,Ubuntu下是可以的,虽然以前没用过拨号上网,不过查了查也不是很麻烦. 打开终端 ...
- ()()()()x()=()()()()填1-9数字
/** Function: ()()()()x()=()()()() Developer: Date: */ #include "iostream" #include " ...
- Bzoj1313 [HAOI2008]下落的圆盘
有 n 个圆盘从天而降,后面落下的可以盖住前面的.最后按掉下的顺序,在平面上依次测得每个圆盘的圆心和半径,问下落完成后从上往下看,整个图形的周长是多少,即你可以看到的圆盘的轮廓的圆盘的轮廓总长.例如下 ...