题意:给出一个图,先求出最大生成树,然后多次询问树上路径\(u→v\)的有向最大极差\(max(a_i-a_j),i>j\),其中\(i\)和\(j\)指代节点在路径中出现的顺序

极差具有单调性和可相交,因此可以用倍增来合并答案求解

维护变量

\(mx[i][j]\):\(i\)节点到\(i\)的第\(2^j\)个祖先的最大值

\(mn[i][j]\):\(i\)节点到\(i\)的第\(2^j\)个祖先的最小值

\(f[i][j]\):\(i\)节点到\(i\)的第\(2^j\)个祖先的最大极差

\(g[i][j]\):\(i\)的第\(2^j\)个祖先到\(i\)节点的最大极差

每次询问就是\(u,lca(u,v),v\)的分类讨论

答案可能是

\(u→lca(u,v)\)的最大极差

\(lca(u,v)→v\)的最大极差

\(u->lca(u,v)\)的最小值和\(lca(u,v)→v\)的最大值的差

注意查询极差时要额外维护\(u/v\)到当前节点的最大/最小值来合并单链的最优解(留意顺序的先后)

还有是先dfs还是先递推的细节问题(WA成狗)

如果问题带修改那就强上树剖吧

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define println(a) printf("%lld\n",(ll)a)
using namespace std;
const int MAXN = 1e5+11;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int to[MAXN<<1],nxt[MAXN<<1],cost[MAXN<<1],head[MAXN],tot;
int pp[MAXN];
int p[MAXN][17],dep[MAXN];
int mn[MAXN][17],mx[MAXN][17];
int f[MAXN][17],g[MAXN][17];
int a[MAXN];
bool vis[MAXN];
struct EDGE{
int from,to,cost;
EDGE(){}
EDGE(int f,int t,int c){
from=f;
to=t;
cost=c;
}
bool operator<(const EDGE &rhs)const{
return cost>rhs.cost;
}
}e[MAXN];
void init(){
memset(head,-1,sizeof head);
memset(f,0,sizeof f);
memset(g,0,sizeof g);
memset(mx,0,sizeof mx);
memset(mn,0x3f,sizeof mn);
memset(vis,0,sizeof vis);
tot=0;
}
void add(int u,int v){
to[tot]=v;
nxt[tot]=head[u];
head[u]=tot++;
}
int find(int x){return x==pp[x]?x:pp[x]=find(pp[x]);}
ll MST(int n,int m){
sort(e+1,e+1+m);
ll ans=0;
rep(i,0,n) pp[i]=i;
rep(i,1,m){
int u=e[i].from;
int v=e[i].to;
int w=e[i].cost;
int aa=find(u),bb=find(v);
if(aa==bb) continue;
pp[aa]=bb;
ans+=1ll*w;
add(u,v); add(v,u);
}
return ans;
}
void dfs(int u,int fa,int d){
dep[u]=d; vis[u]=1;
if(fa==-1) rep(j,0,16) p[u][j]=u,mn[u][j]=mx[u][j]=a[u];
for(int i=head[u];~i;i=nxt[i]){
int v=to[i];
if(v==fa||vis[v]) continue;
rep(j,0,16){
if(j){
p[v][j]=p[p[v][j-1]][j-1];
mx[v][j]=max(mx[v][j-1],mx[p[v][j-1]][j-1]);
mn[v][j]=min(mn[v][j-1],mn[p[v][j-1]][j-1]);
f[v][j]=max(f[v][j-1],f[p[v][j-1]][j-1]);
g[v][j]=max(g[v][j-1],g[p[v][j-1]][j-1]);
f[v][j]=max(f[v][j],mx[p[v][j-1]][j-1]-mn[v][j-1]);
g[v][j]=max(g[v][j],mx[v][j-1]-mn[p[v][j-1]][j-1]);
}else{
p[v][j]=u;
mn[v][j]=min(a[v],a[u]);
mx[v][j]=max(a[v],a[u]);
f[v][j]=a[u]-a[v];
g[v][j]=a[v]-a[u];
}
}
dfs(v,u,d+1);
}
}
int lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int d=dep[u]-dep[v];
rep(j,0,16) if(d>>j&1){
u=p[u][j];
}
if(u==v) return u;
rrep(j,16,0) if(p[u][j]!=p[v][j]){
u=p[u][j];
v=p[v][j];
}
return p[u][0];
}
int MIN(int u,int anc){
int d=dep[u]-dep[anc];
int ans=1<<30;
rep(j,0,16) if(d>>j&1){
ans=min(ans,mn[u][j]);
u=p[u][j];
}
return ans;
}
int MAX(int u,int anc){
int d=dep[u]-dep[anc];
int ans=0;
rep(j,0,16) if(d>>j&1){
ans=max(ans,mx[u][j]);
u=p[u][j];
}
return ans;
}
int LEFT(int u,int anc){
int d=dep[u]-dep[anc];
int ans=0;
int tmin=1<<29;
rep(j,0,16) if(d>>j&1){
ans=max(ans,f[u][j]);
ans=max(ans,mx[u][j]-tmin);
tmin=min(tmin,mn[u][j]);
u=p[u][j];
}
return ans;
}
int RIGHT(int u,int anc){
int d=dep[u]-dep[anc];
int ans=0,tmax=0;
rep(j,0,16) if(d>>j&1){
ans=max(ans,g[u][j]);
ans=max(ans,tmax-mn[u][j]);
tmax=max(tmax,mx[u][j]);
u=p[u][j];
}
return ans;
}
int main(){
int n;
while(~scanf("%d",&n)){
init();
rep(i,1,n) a[i]=read();
int m=read();
rep(i,1,m){
int u=read();
int v=read();
int w=read();
e[i]=EDGE(u,v,w);
}
println(MST(n,m));
rep(i,1,n) if(!vis[i]) dfs(i,-1,1);
int q=read();
while(q--){
int u=read();
int v=read();
int anc=lca(u,v);
int ans=MAX(v,anc)-MIN(u,anc);
ans=max(ans,LEFT(u,anc));
ans=max(ans,RIGHT(v,anc));
println(max(0,ans));
}
}
return 0;
}

ZOJ - 3649 树上倍增的更多相关文章

  1. Social Net ZOJ - 3649

    Social Net ZOJ - 3649 题意: 反正原题题意我是看不懂... 参考:http://www.cnblogs.com/names-yc/p/4922867.html 给出一幅图,求最大 ...

  2. LCA离线Tarjan,树上倍增入门题

    离线Tarjian,来个JVxie大佬博客最近公共祖先LCA(Tarjan算法)的思考和算法实现,还有zhouzhendong大佬的LCA算法解析-Tarjan&倍增&RMQ(其实你们 ...

  3. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  4. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  5. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

  6. [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增

    Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...

  7. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  8. [树上倍增+二分答案][NOIP2012]运输计划

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 公元 2044 年,人类进入了宇宙纪元 L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n− ...

  9. 两种lca的求法:树上倍增,tarjan

    第一种:树上倍增 f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点. 初始条件:f[x][0]=fa[x] 递推式:f[x][k]=f[ f[x][k-1] ][k-1] 一次bfs ...

随机推荐

  1. ECS 游戏架构 实现

    转载自:http://blog.csdn.net/i_dovelemon/article/details/27230719 实现 组件-实体-系统 - 博客频道   这篇文章是在我前面文章,理解组件- ...

  2. Mysql中结果集(mysql_result)与Traversable

    对于MySQL应该也不是很陌生吧,我常常爱犯的以错误就是执行mysli_qurey()后就使用数据,忘记返回的是结果集了.而对于lSELECT,.SHOW, DESCRIBE . EXPLAINmys ...

  3. Android Touch 事件总结

    ---恢复内容开始--- 1.Touch事件传递机制 过程有点儿类似于栈, ViewGroup的子类有都继承它的以下3个方法: public boolean dispatchTouchEvent(Mo ...

  4. ComponentSpace SAML v2.0 for .NET 使用介绍

    下载地址:http://samlsso.codeplex.com/ 以下描叙参考版本为其官网最新版本2.5.0.6.相对2.4版本,2.5有了很大改进,很多接口方法都变了.使用起来更方便,易懂. 广告 ...

  5. 一类适合初学者的DP:最大子段和与最大子矩阵

    最近在水简单DP题,遇到了两道层层递进的DP题,于是记录一下 一.最大子段和 题意: 给出一个长度为n(n<=1e5)的序列,求连续子段的最大值 比如说2 3 -4 5 的最大值是6  而 2 ...

  6. VC中CRect类的简单介绍

    CRect CRect类与Windows RECT结构相似,并且还包括操作CRect对象和Windows RECT结构的成员函数.在传递LPRECT,LPCRECT或RECT结构作为参数的任何地方,都 ...

  7. 【装饰者模式】Decorator Pattern

    装饰者模式,这个模式说我一直记忆深刻的模式,因为Java的IO,我以前总觉得Java的IO是一个类爆炸,自从明白了装饰者模式,Java的IO体系让我觉得非常的可爱,我们现在看看什么是装饰者,然后再来看 ...

  8. sql 计算地球2个坐标之间的距离

    show variables like '%func%'; set global log_bin_trust_function_creators=1; use scm_wuliudelimiter $ ...

  9. Windows store app[Part 3]:认识WinRT的异步机制

    WinRT异步机制的诞生背景 当编写一个触控应用程序时,执行一个耗时函数,并通知UI更新,我们希望所有的交互过程都可以做出快速的反应.流畅的操作感变的十分重要. 在连接外部程序接口获取数据,操作本地数 ...

  10. uwsgi启动提示:probably another instance of uWSGI is running on the same address (:8002). bind(): Address already in use [core/socket.c line 769]

    提示8002端口被占用,可以这样终止掉后再启动 sudo fuser -k 8002/tcp