题目:Yaoge’s maximum profit
题意:一棵树,每个结点有个初始的权值,点的权值代表在该点的鸡肉的价格。
对于一个询问X, Y, V。
找到X到Y的路径,可以选择在路径上一个点I买鸡肉,然后在点J卖掉,要求J必须在I之后访问。那么你就可以赚取差价,问最大差价是多少。然后这条路径上的点的权值全部增加V。
这么裸的树链剖分,我特么T到比赛结束有木有啊!!!!
结束了再看看代码发现有个地方木有赋值,赋了值就AC了有木有啊!!!!
深呼吸。。。冷静。。。
这题又跟HDU4718很像哦,可以参考我之前写的题解。
这道题,首先考虑一条链的版本,我们用线段树来维护,先从区间合并来考虑。
对于当前结点,那么结点的最优值肯定来自于左孩子和右孩子的最优值,以及区间合并的最优值。
区间合并的时候,我们肯定是在左孩子的区间买,在右孩子的区间卖,最大差值肯定是右孩子的最大值-左孩子的最小值。
区间合并搞定了。更新操作也很容易,加个懒惰标记,由于区间内全部加上V值,对于区间内的差价是没有影响的,所以直接累加到标记上就可以。
那么来到这题,变成多条链的合并。我们会发现,如果是从X到Y的方向,求解方法同上。但是如果我们是Y到X的方向,我们应该反过来,即最大差值=左孩子的最大值-右孩子的最小值。
是不是跟HDU4718很像?
所以线段树的结点定义是这样嘀:
struct TreeNode{
int l, r;//左右边界
int Max;//区间里的最大权值
int Min;//区间里的最小权值
int inc;//区间里右边减去左边的最大差值
int des;//区间里左边减去右边的最大差值
int lazy;//懒惰标记
int lch, rch;//左右孩子
};
区间合并的代码,cur, lchd, rchd的定义可参考完整代码里面的宏定义:
void maintain(int o){
cur.Max = max(lchd.Max, rchd.Max);
cur.Min = min(lchd.Min, rchd.Min);
cur.inc = max(rchd.Max-lchd.Min, max(lchd.inc, rchd.inc));
cur.des = max(lchd.Max-rchd.Min, max(lchd.des, rchd.des));
}
其他的定义跟我在HDU4718里的定义都差不多,不清楚的可以参考那边,这里我就不写注释了。
#include
#include
#include
#include
using namespace std;
#define lson tr[o].lch
#define rson tr[o].rch
#define lchd tr[tr[o].lch]
#define rchd tr[tr[o].rch]
#define cur tr[o]
#define pb push_back
const int N = 50010;
vector V[N];
vector G[N];
int T, n, q, path_cnt, node_cnt;
int father[N];
int belong[N];
int top[N];
int size[N];
int rank[N];
int path_size[N];
int path_top[N];
int path_dep[N];
int weight[N];
int tree[N];
struct TreeNode{
int l, r, Max, Min, inc, des, lazy;
int lch, rch;
};
TreeNode tr[N*10];
void dfs(int x, int fa, int dep){
int M = 0;
int key = -1;
size[x] = 1;
for(int i=0; iM){
M = size[j];
key = j;
}
}
belong[x] = 0;
for(int i=0; i>1;
update(lson, cur.l, m, cur.lazy);
update(rson, m+1, cur.r, cur.lazy);
cur.lazy = 0;
}
}
void build(int path, int o, int ll, int rr){
cur.l=ll; cur.r=rr;
cur.lazy = 0;
if(ll>1;
lson = ++node_cnt;
build(path, lson, ll, m);
rson = ++node_cnt;
build(path, rson, m+1, rr);
maintain(o);
}
else{
cur.Max = cur.Min = weight[V[path][ll-1]];
cur.inc = cur.des = 0;
}
}
inline int Merge(int &Max, int &Min, int &Max1, int &Min1, bool f){
int res = f?(Max-Min1):(Max1-Min);
if(Max1>Max) Max = Max1;
if(Min1>1;
pushdown(o);
int res, Max1, Min1;
if(rr<=m) update(lson, ll, rr, v);
else if(ll>m) update(rson, ll, rr, v);
else{
update(lson, ll, m, v);
update(rson, m+1, rr, v);
}
maintain(o);
}
int query(int o, int ll, int rr, int v, bool f, int &Max, int &Min){
if(cur.l==ll && cur.r==rr){
Max = cur.Max;
Min = cur.Min;
cur.Max += v;
cur.Min += v;
cur.lazy += v;
return f?cur.des:cur.inc;
}
int m = (cur.l+cur.r)>>1;
pushdown(o);
int res, Max1, Min1;
if(rr<=m){
res = query(lson, ll, rr, v, f, Max, Min);
}
else if(ll>m){
res = query(rson, ll, rr, v, f, Max, Min);
}
else{
int v1 = query(lson, ll, m, v, f, Max, Min);
int v2 = query(rson, m+1, rr, v, f, Max1, Min1);
int v3 = Merge(Max, Min, Max1, Min1, f);
res = v1>v2?v1:v2;
if(v3>res) res = v3;
}
maintain(o);
return res;
}
void init(){
path_cnt = node_cnt = 0;
dfs(1, 0, 1);
father[1] = 0;
path_dep[belong[1]] = 0;//这句话忘写就不能AC呀!!!!
path_size[belong[1]] = rank[1];
for(int i=1; i<=path_cnt; i++){
tree[i] = ++node_cnt;
build(i, tree[i], 1, path_size[i]);
}
}
int Q(int a, int b, int c){
int x = belong[a];
int y = belong[b];
bool mk1=0, mk2=0;
int Max1, Max2, Min1, Min2, Max, Min;
int ans = 0, tmp;
while(x!=y){
if(path_dep[x]>path_dep[y]){
tmp = query(tree[x], rank[a], path_size[x], c, 0, Max, Min);
if(tmp>ans) ans = tmp;
if(mk1){
tmp = Merge(Max1, Min1, Max, Min, 0);
if(tmp>ans) ans = tmp;
}
else{
Max1 = Max;
Min1 = Min;
mk1 = 1;
}
a = father[path_top[x]];
x = belong[a];
}
else{
tmp = query(tree[y], rank[b], path_size[y], c, 1, Max, Min);
if(tmp>ans) ans = tmp;
if(mk2){
tmp = Merge(Max2, Min2, Max, Min, 1);
if(tmp>ans) ans = tmp;
}
else{
Max2 = Max;
Min2 = Min;
mk2 = 1;
}
b = father[path_top[y]];
y = belong[b];
}
}
if(rank[a]>rank[b]){
tmp = query(tree[x], rank[b], rank[a], c, 1, Max, Min);
}
else{
tmp = query(tree[x], rank[a], rank[b], c, 0, Max, Min);
}
if(tmp>ans) ans = tmp;
if(mk1){
tmp = Merge(Max1, Min1, Max, Min, 0);
if(tmp>ans) ans = tmp;
}
else{
Max1 = Max;
Min1 = Min;
}
//printf("%d %d %d %d\n", Max1, Min1, Max2, Min2);
if(mk2){
tmp = Merge(Max1, Min1, Max2, Min2, 0);
if(tmp>ans) ans = tmp;
}
return ans;
}
int main(){
//freopen("K.txt", "r", stdin);
int size = 32 << 20;
char *p = (char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p));
scanf("%d", &T);
for(int t=1; t<=T; t++){
scanf("%d", &n);
for(int i=1; i<=n; i++){
G[i].clear();
scanf("%d", weight+i);
}
int a, b, c;
for(int i=1; i