题目大意:

给出一棵树。每一个点有商店。每一个商店都有一个价格,Yaoge每次从x走到y都能够在一个倒卖商品,从中得取利益。当然,买一顶要在卖之前。可是没次走过一条路,这条路上的全部商品都会添加一个v。

输出每次的最大利益。

思路分析:

非常easy想到树链剖分,但是关键在于怎样维护这样一个变量。使得每次都要让买的再卖的前面。

维护变量 ltr 和 rtl 。表示从左去右和从右去左。

剖分熟练的时候。推断x 和 y的深度,一步一步往上爬。

然后维护区间最大值和最小值。爬的时候更新答案。

。。。4921ms...小孩子不要看。。。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#pragma comment(linker,"/STACk:10240000,10240000")
#define maxn 50005
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define lson num<<1,s,mid
#define rson num<<1|1,mid+1,e
using namespace std;
typedef long long ll;
int next[maxn<<1],to[maxn<<1],head[maxn],tot;//临界表
int pre[maxn],root[maxn],siz[maxn],son[maxn],w[maxn],dep[maxn],id;//原树的父亲 链上的根 siz 有最大siz的子树 又一次分配的id 深度 getid中来计数的
ll ltr[maxn<<2],rtl[maxn<<2],mx[maxn<<2],mn[maxn<<2],add[maxn<<2];//线段树变量
int n;
void init()
{
pre[1]=0;
dep[1]=0;
tot=0;id=0;
memset(head,0,sizeof head);
memset(add,0,sizeof add);
memset(mn,0,sizeof mn);
memset(mx,0,sizeof mx);
memset(ltr,0,sizeof ltr);
memset(rtl,0,sizeof rtl);
}
void addedge(int u,int v)
{
tot++;
next[tot]=head[u];
to[tot]=v;
head[u]=tot;
}
void dfs(int now)//to get size,son,dep,pre...
{
son[now]=0;
siz[now]=1;
for(int p =head[now]; p ; p=next[p])
{
int t=to[p];
if(t!=pre[now])
{
pre[t]=now;
dep[t]=dep[now]+1;
dfs(t);
if(siz[t]>siz[son[now]])son[now]=t;
siz[now]+=siz[t];
}
}
}
void getid(int now,int rt)//to get w and root...
{
w[now]=++id;
root[now]=rt;
if(son[now])getid(son[now],rt);
for(int p = head[now] ; p ; p=next[p])
{
int t=to[p];
if(t!=son[now]&&t!=pre[now])
getid(t,t);
}
}
void pushdown(int num,int s,int e)
{
if(add[num])
{
int mid=(s+e)>>1;
mx[num<<1]+=add[num];
mx[num<<1|1]+=add[num];
mn[num<<1]+=add[num];
mn[num<<1|1]+=add[num];
add[num<<1]+=add[num];
add[num<<1|1]+=add[num];
add[num]=0;
}
}
void pushup(int num)
{
mx[num]=max(mx[num<<1],mx[num<<1|1]);
mn[num]=min(mn[num<<1],mn[num<<1|1]);
ltr[num]=max(mx[num<<1|1]-mn[num<<1],max(ltr[num<<1],ltr[num<<1|1]));
rtl[num]=max(mx[num<<1]-mn[num<<1|1],max(rtl[num<<1],rtl[num<<1|1]));
if(ltr[num]<0)ltr[num]=0;
if(rtl[num]<0)rtl[num]=0;
} void update(int num,int s,int e,int l,int r,int val)
{
if(l<=s && r>=e)
{
add[num]+=val;
mx[num]+=val;
mn[num]+=val;
return;
}
pushdown(num,s,e);
int mid=(s+e)>>1;
if(l<=mid)update(lson,l,r,val);
if(r>mid)update(rson,l,r,val);
pushup(num);
}
ll query(int num,int s,int e,int l,int r,int flg,ll &maxv,ll &minv)
{
if(l<=s && r>=e)
{
maxv=mx[num];
minv=mn[num];
if(flg)return ltr[num];
else return rtl[num];
}
int mid=(s+e)>>1;
pushdown(num,s,e);
if(r<=mid)return query(lson,l,r,flg,maxv,minv);
else if(l>mid)return query(rson,l,r,flg,maxv,minv);
else
{
ll r1,r2,n1,n2,m1,m2,ans;
r1=query(lson,l,mid,flg,m1,n1);
r2=query(rson,mid+1,r,flg,m2,n2);
maxv=max(m1,m2);
minv=min(n1,n2);
if(flg)
{
ans=max(r1,r2);
ans=max(ans,m2-n1);
}
else
{
ans=max(r1,r2);
ans=max(ans,m1-n2);
}
ans=max(0LL,ans);
return ans;
}
} ll fuck(int x,int y)
{
ll ans=0,maxx,minx,maxy,miny,rx,ry;
ll tmax,tmin,tr;
maxx=maxy=0;
minx=miny=Inf;
rx=ry=0;
while(root[x]!=root[y])
{
if(dep[root[x]]<dep[root[y]])
{
tr=query(1,1,n,w[root[y]],w[y],1,tmax,tmin);
ry=max(ry,tr);
ry=max(ry,maxy-tmin);
maxy=max(maxy,tmax);
miny=min(miny,tmin);
ans=max(ans,ry);
y=pre[root[y]];
}
else
{
tr=query(1,1,n,w[root[x]],w[x],0,tmax,tmin);
rx=max(rx,tr);
rx=max(rx,tmax-minx);
maxx=max(tmax,maxx);
minx=min(tmin,minx);
ans=max(ans,rx);
x=pre[root[x]];
}
}
if(dep[x]<dep[y])
{
tr=query(1,1,n,w[x],w[y],1,tmax,tmin);
ans=max(ans,tr);
ans=max(ans,maxy-tmin);
maxy=max(tmax,maxy);
miny=min(tmin,miny);
ans=max(ans,maxy-minx);
}
else
{
tr=query(1,1,n,w[y],w[x],0,tmax,tmin);
ans=max(ans,tr);
ans=max(ans,tmax-minx);
maxx=max(tmax,maxx);
minx=min(tmin,minx);
ans=max(ans,maxy-minx);
}
return ans;
}
void work(int x,int y,int val)
{
while(root[x]!=root[y])
{
if(dep[root[x]]<dep[root[y]])swap(x,y);
update(1,1,n,w[root[x]],w[x],val);
x=pre[root[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(1,1,n,w[x],w[y],val);
}
int save[maxn]; inline void scanf_(int &num){
char in;
bool neg=false;
while(((in=getchar()) > '9' || in<'0') && in!='-') ;
if(in=='-'){
neg=true;
while((in=getchar()) >'9' || in<'0');
}
num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
num*=10,num+=in-'0';
if(neg)
num=0-num;
}
inline void printf_(ll num){
bool flag=false;
if(num<0){
putchar('-');
num=-num;
}
int ans[20],top=0;
while(num!=0){
ans[top++]=num%10;
num/=10;
}
if(top==0)
putchar('0');
for(int i=top-1;i>=0;i--){
char ch=ans[i]+'0';
putchar(ch);
}
puts("");
} int main()
{
int T;
scanf_(T);
while(T--)
{
init();
scanf_(n);
for(int i=1;i<=n;i++)
scanf_(save[i]);
for(int i=1;i<=n-1;i++)
{
int s,e;
scanf_(s);scanf_(e);
addedge(s,e);
addedge(e,s);
}
dfs(1);
getid(1,1);
for(int i=1;i<=n;i++)
update(1,1,n,w[i],w[i],save[i]);
char str[5];
int Q;
scanf_(Q);
while(Q--)
{
int x,y,v;
scanf_(x);
scanf_(y);
scanf_(v);
printf_(fuck(x,y));
work(x,y,v);
}
}
return 0;
}

Hdu 5052 Yaoge’s maximum profit(树链剖分)的更多相关文章

  1. HDU 5052 Yaoge’s maximum profit 光秃秃的树链拆分 2014 ACM/ICPC Asia Regional Shanghai Online

    意甲冠军: 特定n小点的树权. 以下n每一行给出了正确的一点点来表达一个销售点每只鸡价格的格 以下n-1行给出了树的侧 以下Q操作 Q行 u, v, val 从u走v,程中能够买一个鸡腿,然后到后面卖 ...

  2. HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  3. HDU 4897 Little Devil I(树链剖分)(2014 Multi-University Training Contest 4)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4897 Problem Description There is an old country and ...

  4. HDU 5274 Dylans loves tree(树链剖分)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5274 [题目大意] 给出一棵树,每个点有一个权值,权值可修改,且大于等于0,询问链上出现次数为奇数 ...

  5. hdu 3966 Aragorn&#39;s Story(树链剖分+树状数组)

    pid=3966" target="_blank" style="">题目链接:hdu 3966 Aragorn's Story 题目大意:给定 ...

  6. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  7. HDU - 3966 Aragorn's Story(树链剖分入门+线段树)

    HDU - 3966 Aragorn's Story Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & ...

  8. (中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

    Problem Description   Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are ...

  9. hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...

随机推荐

  1. CakePHP调用model类和foreach循环

    1. 引入Model类 2.调用model类(Guarantee)下的getCity()方法 3.写sql语句 并返回获得值 4.foreach循环取得的城市

  2. 使用装饰器减少try ...finally的重复使用

    @util.try_except_bskgk def added_user_handle(cur, search_time): added_user_sql = """ ...

  3. js原生日历

    突然发现日期对象可以进行 加减 , 利用这个特性写了一个可以说是对只要会JavaScript  的就可以写的日历:没有各种算法,只有一些逻辑相信只要懂javascript就差不多看俩眼就会的日历. & ...

  4. 在PHP中使用加密技术

    Gpg4win 是一款基于 GPG 的非对称加密软件.非对称加密方式,简单理解就是用公钥加密文件,用私钥解密文件.如果你需要发送加密信息,首先获取接收者的公钥,然后利用该公钥加密后传递,对方利用对应的 ...

  5. <Android 应用 之路> MPAndroidChart~PieChart

    简介 MPAndroidChart是PhilJay大神给Android开发者带来的福利.MPAndroidChart是一个功能强大并且使用灵活的图表开源库,支持Android和IOS两种,这里我们暂时 ...

  6. EF Migrations

    Enable-Migrations -EnableAutomaticMigrations dbcontent Add-Migration XXXXX Update-Database -Verbose ...

  7. Two ways to assign values to member variables

    setXxx()方法,带参数的构造方法.类名作为形式参数,其实里面需要传入一个该类的对象.类名作为返回值,其实返回的是一个该类的对象.

  8. 我的CSDN博客&Github地址

    我的 CSDN 博客地址: https://blog.csdn.net/qq_40147863 Github 地址: https://github.com/xpwi

  9. ffmpeg 简介及使用

    简介 ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url ...

  10. CentOS7 安装 JIRA 7.2.x 教程:下载、安装、汉化、破解

    1.先看视频,参考着能装出个试用版来,不同的地方后面再做说明.JIRA 安装视频(Linux) http://www.confluence.cn/pages/viewpage.action?pageI ...