Yaoge’s maximum profit

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 982    Accepted Submission(s): 274

Problem Description
Yaoge likes to eat chicken chops late at night. Yaoge has eaten too many chicken chops, so that Yaoge knows the pattern in the world of chicken chops. There are N cities in the world numbered from 1 to N . There are some roads between some cities, and there is one and only one simple path between each pair of cities, i.e. the cities are connected like a tree. When Yaoge moves along a path, Yaoge can choose one city to buy ONE chicken chop and sell it in a city after the city Yaoge buy it. So Yaoge can get profit if Yaoge sell the chicken chop with higher price. Yaoge is famous in the world. AFTER Yaoge has completed one travel, the price of the chicken chop in each city on that travel path will be increased by V .
 
Input
The first line contains an integer T (0 < T ≤ 10), the number of test cases you need to solve. For each test case, the first line contains an integer N (0 < N ≤ 50000), the number of cities. For each of the next N lines, the i-th line contains an integer Wi(0 < Wi ≤ 10000), the price of the chicken chop in city i. Each of the next N - 1 lines contains two integers X Y (1 ≤ X, Y ≤ N ), describing a road between city X and city Y . The next line contains an integer Q(0 ≤ Q ≤ 50000), the number of queries. Each of the next Q lines contains three integer X Y V(1 ≤ X, Y ≤ N ; 0 < V ≤ 10000), meaning that Yaoge moves along the path from city X to city Y , and the price of the chicken chop in each city on the path will be increased by V AFTER Yaoge has completed this travel.
 
Output
For each query, output the maximum profit Yaoge can get. If no positive profit can be earned, output 0 instead.
 
Sample Input
1
5
1
2
3
4
5
1 2
2 3
3 4
4 5
5
1 5 1
5 1 1
1 1 2
5 1 1
1 2 1
 
Sample Output
4
0
0
1
0
/*
hdu 5052 树链剖分(nice) problem:
给你一个树,每次找出u->v上面的最大差值(较小值必需在较大值前面).找出后在给路径所有点加上w solve:
首先是线段树维护差值的问题,在这里错了很久- -. 按照以前的写习惯了,并没想区间合并时候的问题...
树链剖分查找的时候,每次只能查找一条链,所以在这里也要合并(右边链Max - 左边链Min).
而且u->v的话,因为u到(u,v)的lca的节点号是逆序的(根节点较小),所以线段树要维护 左到右and右到左的差值 hhh-2016-08-22 10:53:40
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#define lson i<<1
#define rson i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define key_val ch[ch[root][1]][0]
#define inf 0x3FFFFFFFFFFFFFFFLL
using namespace std;
const int maxn = 200100;
int head[maxn],tot,pos,son[maxn];
int top[maxn],fp[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn];
int n;
ll a[maxn]; ll MAX(ll a,ll b)
{
return a>b?a:b;
}
ll MIN(ll a,ll b)
{
return a>b?b:a;
}
struct Edge
{
int to,next;
} edge[maxn<<2]; void ini()
{
tot = 0,pos = 1;
clr(head,-1),clr(son,-1);
} void add_edge(int u,int v)
{
edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;
} void dfs1(int u,int pre,int d)
{
// cout << u << " " <<pre <<" " <<d <<endl;
dep[u] = d;
fa[u] = pre,num[u] = 1;
for(int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].to;
if(v != pre)
{
dfs1(v,u,d+1);
num[u] += num[v];
if(son[u] == -1 || num[v] > num[son[u]])
son[u] = v;
}
}
} void getpos(int u,int sp)
{
top[u] = sp;
p[u] = pos++;
fp[p[u]] = u;
if(son[u] == -1)return ;
getpos(son[u],sp);
for(int i = head[u]; ~i ; i = edge[i].next)
{
int v = edge[i].to;
if(v != son[u] && v != fa[u])
getpos(v,v);
}
} struct node
{
int l,r,mid;
ll Max,Min;
ll lans,rans;
ll add;
} tree[maxn << 2]; void push_up(int i)
{
tree[i].Max = MAX(tree[lson].Max,tree[rson].Max);
tree[i].Min = MIN(tree[lson].Min,tree[rson].Min);
tree[i].rans = MAX(tree[rson].Max - tree[lson].Min,MAX(tree[lson].rans,tree[rson].rans));
tree[i].lans = MAX(tree[lson].Max - tree[rson].Min,MAX(tree[lson].lans,tree[rson].lans));
if(tree[i].lans < 0) tree[i].lans = 0;
if(tree[i].rans < 0) tree[i].rans = 0;
} void build(int i,int l,int r)
{
tree[i].l = l,tree[i].r = r;
tree[i].mid=(l+r) >>1;
tree[i].add = 0;
tree[i].Max = 0,tree[i].Min = inf;
tree[i].lans = 0,tree[i].rans = 0;
if(l == r)
{
tree[i].Max = tree[i].Min = a[fp[l]];
return;
}
build(lson,l,tree[i].mid);
build(rson,tree[i].mid+1,r);
push_up(i);
}
void update(int i,ll d)
{
tree[i].Max += d,tree[i].Min += d;
tree[i].add += d;
} void push_down(int i)
{
if(tree[i].add)
{
update(lson,tree[i].add),update(rson,tree[i].add);
tree[i].add = 0;
}
} void update_area(int i,int l,int r,ll val)
{
if(tree[i].l >= l && tree[i].r <= r)
{
update(i,val);
return ;
}
push_down(i);
int mid = tree[i].mid;
if(l <= mid)
update_area(lson,l,r,val);
if(r > mid)
update_area(rson,l,r,val);
push_up(i);
} ll query(int i,int l,int r,int flag,ll& MaxPrice,ll& MinPrice)
{
if(tree[i].l >= l && tree[i].r <= r)
{
MinPrice = tree[i].Min;
MaxPrice = tree[i].Max;
if(flag)
{ return tree[i].rans;
}
else
{
return tree[i].lans;
}
}
push_down(i);
int mid = tree[i].mid;
if(r <= mid)
return MAX(0LL,query(lson,l,r,flag,MaxPrice,MinPrice));
else if(l > mid)
return MAX(0LL,query(rson,l,r,flag,MaxPrice,MinPrice));
else
{
ll ta = 0;
ll max1,max2,min1,min2;
ll ans = MAX(query(lson,l,mid,flag,max1,min1),query(rson,mid+1,r,flag,max2,min2));
if(flag)
ta = max2 - min1;
else
ta = max1 - min2;
MaxPrice = MAX(max1,max2);
MinPrice = MIN(min1,min2);
ta = MAX(ta,0LL);
return MAX(ans,ta);
}
push_up(i);
} void make_add(int u,int v,ll val)
{
int f1 = top[u],f2 = top[v];
while(f1 != f2)
{
if(dep[f1] < dep[f2])
{
swap(f1,f2),swap(u,v);
}
update_area(1,p[f1],p[u],val);
u = fa[f1],f1 = top[u];
}
if(dep[u] > dep[v])
swap(u,v);
update_area(1,p[u],p[v],val);
return ;
} ll make_query(int u,int v)
{
ll tmin,tmax,tMin,tMax;
ll cmin,cmax,cMin,cMax;
tMin = tmin = tree[1].Max;
tMax = tmax = 0;
ll cnt = 0;
int f1 = top[u],f2 = top[v];
while(f1 != f2)
{
if(dep[f1] > dep[f2])
{
// cout << p[f1] <<" "<<p[u] <<endl;
cnt = MAX(cnt,query(1,p[f1],p[u],0,cmax,cmin));
cnt = MAX(cnt,cmax - tmin);
cnt = MAX(cnt,tMax - cmin);
tmin = MIN(cmin,tmin);
tmax = MAX(cmax,tmax);
u = fa[f1],f1 = top[u];
// tmax = max(tmax,cmax);
}
else
{
// cout << p[f2] <<" "<<p[v] <<endl;
cnt = MAX(cnt,query(1,p[f2],p[v],1,cMax,cMin));
cnt = MAX(cnt,tMax - cMin);
cnt = MAX(cnt,cMax-tmin);
tMax = MAX(tMax,cMax);
tMin = MIN(tMin,cMin);
v = fa[f2],f2 = top[v];
// tMin = min(tMin,cMin);
}
}
if(dep[u] > dep[v])
{
cnt =MAX(cnt,query(1,p[v],p[u],0,cmax,cmin));
cnt =MAX(cnt,cmax-tmin);
tmin = MIN(tmin,cmin);
cnt = MAX(cnt,tMax-tmin);
}
else
{
cnt =MAX(cnt,query(1,p[u],p[v],1,cMax,cMin));
// cout <<"max" <<cMax <<" " <<"min" <<cMin <<endl;
cnt = MAX(cnt,tMax-cMin);
tMax = MAX(tMax,cMax);
cnt = MAX(cnt,tMax-tmin);
}
return cnt;
} /*
5
3 1 1 1
1 2 2 3
3
1 1 500000000
2 1 1
3 1 1
*/
int main()
{
// freopen("in.txt","r",stdin);
int T;
int m,u,v;
ll w;
scanf("%d",&T);
while(T--)
{
ini();
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%I64d",&a[i]);
for(int i =1; i <n; i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,0,0);
getpos(1,1);
build(1,1,pos-1);
scanf("%d",&m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d%I64d",&u,&v,&w);
printf("%I64d\n",make_query(u,v));
make_add(u,v,w);
}
}
return 0;
}

  

hdu 5052 树链剖分的更多相关文章

  1. HDU 5052 /// 树链剖分+线段树区间合并

    题目大意: 给定n (表示树有n个结点) 接下来n行给定n个点的点权(在这个点上买鸡或者卖鸡的价钱就是点权) 接下来n-1行每行给定 x y 表示x结点和y结点之间有一条边 给定q (表示有q个询问) ...

  2. hdu 5893 (树链剖分+合并)

    List wants to travel Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/O ...

  3. hdu 4897 树链剖分(重轻链)

    Little Devil I Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  4. hdu 5274 树链剖分

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  5. HDU 3966 (树链剖分+线段树)

    Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板 ...

  6. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  7. HDU 3966 /// 树链剖分+树状数组

    题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...

  8. hdu 4729 树链剖分

    思路:这个树链剖分其实还是比较明显的.将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数.当A<=B时,就全部建新的管子. 对于A>B的情况比较 建一条 ...

  9. hdu 3966 树链剖分

    思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...

随机推荐

  1. Beta冲刺计划---Day0

    Beta阶段报告---Day0 1.需要改进完善的功能   我们上一阶段开发由于开发时间匆忙,对于爬虫耗时的优化没有考虑.优化的空间我在Alpha阶段的总结报告里说过,具体看下图.   这张图显示出爱 ...

  2. oc中protocol、category和继承的区别

    OC中protocol.category和继承的区别以前还是有点迷糊,面试的时候说的有点混乱,现在结合一些资料总结一下. 利用继承,多态是一个很好的保持"对扩展开放.对更改封闭"( ...

  3. 详解JavaScript对象继承方式

    一.对象冒充 其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式).因为构造函数只是一个函数,所以可使 Parent 构造函数成为 Children 的方法,然 ...

  4. ELK学习总结(2-5)elk的版本控制

    ----------------------------------------------------------------- 1.悲观锁和乐观锁 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据 ...

  5. 页面加载loading动画

    关于页面加载的loading动画,能度娘到的大部分都是通过定时器+蒙层实现的,虽然表面上实现了动画效果,实际上动化进程和页面加载进程是没有什么关系的,只是设置几秒钟之后关闭蒙层,但假如页面须要加载的元 ...

  6. jquery实现链接的title快速出现

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  7. python flask框架 蓝图的使用

    蓝图的目的是实现 各个模块的视图函数写在不同的py文件当中. 主视图 中 导入 分路由视图的模块,并且注册蓝图对象 分路由视图中 利用 蓝图对象 的route 进行装饰视图函数 主路由视图函数: #c ...

  8. IDEA安装和JDK的配置

    安装: 免费获取注册码:   http://idea.lanyus.com/ 将其压缩包解压后:  应用程序在bin目录下 打开之后: 选择第二个,输入刚获取的验证码: 成功. 如果没有安装JDK报错 ...

  9. IT技术有感

    今天看技术文章,spring相关的,某一个点以前每次看一直不理解, 可是不知道为什么隔了1年左右,中间什么都没做,现在却都懂了. 在看懂的那一刻,笼罩在我心上的躁动突然平静了许多,我的心这一年来前所未 ...

  10. MySQL5.7.21解压版安装详细教程以及一些问题的解决

    笔者是最近玩mysql的时候玩坏了,想写点东西记录下.我安装的是MySQL5.7.21,安装之后没有my.ini文件. 遇到了2个问题,一是mysql服务启动不了,被my.ini整了,二是root密码 ...