集训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\)天中,每天早晨他会从一段编号连续的花中选择一盆摆放在客厅, 并在晚上放回. 同时每天有特定的 ...
随机推荐
- Codeforces Round #390 (Div. 2) E(bitset优化)
题意就是一个给出2个字符矩阵,然后进行匹配,输出每个位置的匹配的结果 (超出的部分循环处理) 一种做法是使用fft,比较难写,所以没有写 这里使用一个暴力的做法,考虑到一共只出现26个字符 所以使用一 ...
- [洛谷P1536]村村通
题意:多组数据,当n为0时结束,每组数据表示有n个村子,m条路,求还需要建多少条路,使得所有的村子联通题解:用并查集求出有多少个联通块,然后求解 C++ Code: #include<cstdi ...
- php: Can't use function return value in write context
关于empty()函数, php手册中提到,php5.5之前empty()函数只支持检查变量,传入任何其他的表达式或函数都会产生语法错误. Note: Prior to PHP 5.5, empty( ...
- Any gotchas at all with converting from MyISAM to InnoDB?
Q: I'm ready to move from MyISAM to InnoDB but wanted to know if there was a full list of things to ...
- 第五届华中区程序设计邀请赛暨武汉大学第十四届校赛 网络预选赛 A
Problem 1603 - Minimum Sum Time Limit: 2000MS Memory Limit: 65536KB Total Submit: 564 Accepted: ...
- POI2007 MEG-Megalopolis [树状数组]
MEG-Megalopolis 题目描述 Byteotia has been eventually touched by globalisation, and so has Byteasar the ...
- activity栈清空
http://blog.csdn.net/swjtuxu/article/details/26163737
- bzoj2424 [HAOI2010]订货 dp+单调性
[HAOI2010]订货 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1311 Solved: 884[Submit][Status][Discu ...
- Java多线程1:Java中sleep,wait,yield,join的区别
1.sleep()方法 在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”.不推荐使用. sleep()使当前线程进入阻塞状态,在指定时间内不会执行. 2.wait()方法 在其他线程调用 ...
- js删除一个父元素下面的所有子元素
比如<div id="ok"><button tpye='button'>111111</button><p>22222</p ...