hdu 5052 树链剖分
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
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
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 树链剖分的更多相关文章
- HDU 5052 /// 树链剖分+线段树区间合并
题目大意: 给定n (表示树有n个结点) 接下来n行给定n个点的点权(在这个点上买鸡或者卖鸡的价钱就是点权) 接下来n-1行每行给定 x y 表示x结点和y结点之间有一条边 给定q (表示有q个询问) ...
- hdu 5893 (树链剖分+合并)
List wants to travel Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/O ...
- hdu 4897 树链剖分(重轻链)
Little Devil I Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others ...
- hdu 5274 树链剖分
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- HDU 3966 (树链剖分+线段树)
Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板 ...
- hdu 3966(树链剖分+线段树区间更新)
传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...
- HDU 3966 /// 树链剖分+树状数组
题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...
- hdu 4729 树链剖分
思路:这个树链剖分其实还是比较明显的.将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数.当A<=B时,就全部建新的管子. 对于A>B的情况比较 建一条 ...
- hdu 3966 树链剖分
思路:树链剖分入门题,我这门入得好苦啊,程序很快写出来了,可是在LCA过程中把update函数里的左右边界位置写反了,一直RE到死. #pragma comment(linker, "/ST ...
随机推荐
- 项目Alpha冲刺Day11
一.会议照片 二.项目进展 1.今日安排 熟悉框架的使用以及编写用户查看的界面以及该页面内的操作. 2.问题困难 全局的日期转换出现问题,在序列化的时候是按照配置来的,但是反序列化的时候就错了,问题待 ...
- LoadRunner录制手机APP教程
1. 开启fiddler 2. 打开HP Virtual User Generator,新建->Web (HTTP/HTML)>创建 3. 点击开始录制: (1) ...
- MSSQL 2000 错误823恢复
一.故障描述 MSSQL Server 2000 附加数据库错误823,附加数据库失败.数据库没有备份,不能通过备份恢复数据库,急需恢复数据库中的数据. 二.故障分析SQL Server数据库 823 ...
- JAVA_SE基础——40.super关键字
只要this关键字掌握了,super关键字不在话下,因为他们原理都差不多的.. this&super 什么是this,this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针 ...
- thinkphp框架调用类不存在的方法
thinkphp框架调用类不存在的方法调用类不存在的方法,不会报错,但是也不会执行,这是根据tp框架里面的一个魔术方法,框架里面一共才十几个魔术方法
- MySQL“Another MySQL daemon already running with the same unix socket” 报错信息处理
Mysql "Another Mysql daemon already running with the same unix socket" 解决办法:rm var/lib/mys ...
- Python内置函数(32)——all
英文文档: all(iterable) Return True if all elements of the iterable are true (or if the iterable is empt ...
- 离线Chrome插件安装文件(crx)的安装方法
离线Chrome插件安装文件(crx)的安装方法 一.正常安装方法 1.开发谷歌浏览器,设置->扩展程序 在打开的谷歌浏览器的扩展管理器中用户可以看到一些已经安装程序的Chrome插件,或者一个 ...
- hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(2)安装hadoop
一.依赖安装 安装JDK 二.文件准备 hadoop-2.7.3.tar.gz 2.2 下载地址 http://hadoop.apache.org/releases.html 三.工具准备 3.1 X ...
- 从感知机到 SVM,再到深度学习(一)
在上篇博客中提到,如果想要拟合一些空间中的点,可以用最小二乘法,最小二乘法其实是以样例点和理论值之间的误差最小作为目标.那么换个场景,如果有两类不同的点,而我们不想要拟合这些点,而是想找到一条 ...