题意很简单

给一个树(n < 5w) 每个点有个权值,代表商品价格

若干个询问(5w)

对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品,   最大可能是多少

注意一条路径上只能买卖一次,先买才能卖

  • *分析:先求出点u,v的最近公共祖先f,然后求u->f->v的利润最大值maxval
  •  
    对于这个maxval可能有三种情况:
  •  
    1:maxval是u->f的maxval
  •  
    2:maxval是f->v的maxval
  •  
    3:maxval是u->f的最小w[i]减去f->v的最大w[i]
  •  
    分析到这很明显需要设置4个变量来求maxval:
  •  
    up[u]表示u->f的最大maxval
  •  
    down[u]表示f->u的最大maxval
  •  
    maxw[u]表示u-f的最大w[i]
  •  
    minw[u]表示u-f的最小w[i]
  •  
    所以maxval=max(max(up[u],down[v]),maxw[v]-minw[u]);
  •  
    现在问题就是如何快速的求出这四个变量,在这里我们可以对u,v的LCA(u,v)进行分类解决
  •  
    对于LCA(u,v)是f的询问全部求出,然后再求LCA(u,v)是f的父亲的询问
  •  
    这样当我们求LCA(u,v)是f的父亲的询问的时候就可以借用已经求出的LCA(u,v)是f的询问
  •  
    的结果,这样就不用反复去求u->f的那四个变量值,u->father[f]也能快速求出
  •  
    这个变化主要在寻找father[v]这个过程中进行,具体看代码
  • /*分析:先求出点u,v的最近公共祖先f,然后求u->f->v的利润最大值maxval
    对于这个maxval可能有三种情况:
    1:maxval是u->f的maxval
    2:maxval是f->v的maxval
    3:maxval是u->f的最小w[i]减去f->v的最大w[i]
    分析到这很明显需要设置4个变量来求maxval:
    up[u]表示u->f的最大maxval
    down[u]表示f->u的最大maxval
    maxw[u]表示u-f的最大w[i]
    minw[u]表示u-f的最小w[i]
    所以maxval=max(max(up[u],down[v]),maxw[v]-minw[u]);
    现在问题就是如何快速的求出这四个变量,在这里我们可以对u,v的LCA(u,v)进行分类解决
    对于LCA(u,v)是f的询问全部求出,然后再求LCA(u,v)是f的父亲的询问
    这样当我们求LCA(u,v)是f的父亲的询问的时候就可以借用已经求出的LCA(u,v)是f的询问
    的结果,这样就不用反复去求u->f的那四个变量值,u->father[f]也能快速求出
    这个变化主要在寻找father[v]这个过程中进行,具体看代码
    */
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <cmath>
    #include <iomanip>
    #define INF 99999999
    typedef long long LL;
    using namespace std; const int MAX=+;
    int n,m,size;
    int uu[MAX],vv[MAX],ww[MAX],sum[MAX];
    int up[MAX],down[MAX],maxw[MAX],minw[MAX],father[MAX];
    int head[MAX],head2[MAX],head3[MAX];
    bool mark[MAX]; struct Edge{
    int v,id,next;
    Edge(){}
    Edge(int V,int ID,int NEXT):v(V),id(ID),next(NEXT){}
    }edge[MAX*],edge2[MAX*],edge3[MAX*]; void Init(int num){
    for(int i=;i<=num;++i)head[i]=head2[i]=head3[i]=-,mark[i]=false;
    size=;
    }
    void InsertEdge(int u,int v,int id){
    edge[size]=Edge(v,id,head[u]);
    head[u]=size++;
    }
    void InsertEdge2(int u,int v,int id){
    edge2[size]=Edge(v,id,head2[u]);
    head2[u]=size++;
    }
    void InsertEdge3(int u,int v,int id){
    edge3[size]=Edge(v,id,head3[u]);
    head3[u]=size++;
    }
    int findset(int v){
    if(v == father[v])return father[v];
    int fa=father[v];
    father[v]=findset(father[v]);
    up[v]=max(max(up[v],up[fa]),maxw[fa]-minw[v]);
    down[v]=max(max(down[v],down[fa]),maxw[v]-minw[fa]);
    maxw[v]=max(maxw[v],maxw[fa]);
    minw[v]=min(minw[v],minw[fa]);
    return father[v];
    }
    void LCA(int u){
    mark[u]=true;
    father[u]=u;
    for(int i=head2[u];i != -;i=edge2[i].next){//对LCA(u,v)进行分类
    int v=edge2[i].v,id=edge2[i].id;
    if(!mark[v])continue;
    int f=findset(v);
    InsertEdge3(f,v,id);
    }
    for(int i=head[u];i != -;i=edge[i].next){
    int v=edge[i].v;
    if(mark[v])continue;
    LCA(v);
    father[v]=u;
    }
    for(int i=head3[u];i != -;i=edge3[i].next){
    int id=edge3[i].id;
    findset(uu[id]);
    findset(vv[id]);
    sum[id]=max(max(up[uu[id]],down[vv[id]]),maxw[vv[id]]-minw[uu[id]]);
    }
    }
    int main(){
    int u,v;
    while(~scanf("%d",&n)){
    Init(n);
    for(int i=;i<=n;++i){
    scanf("%d",ww+i);
    up[i]=down[i]=;
    maxw[i]=minw[i]=ww[i];
    }
    for(int i=;i<n;++i){
    scanf("%d%d",&u,&v);
    InsertEdge(u,v,i);
    InsertEdge(v,u,i);
    }
    size=;
    scanf("%d",&m);
    for(int i=;i<m;++i){
    scanf("%d%d",&uu[i],&vv[i]);
    InsertEdge2(uu[i],vv[i],i);
    InsertEdge2(vv[i],uu[i],i);
    }
    size=;
    LCA();
    for(int i=;i<m;++i)printf("%d\n",sum[i]);
    }
    return ;
    }

RMQ做法

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef long long LL;
using namespace std; const int MAX=+;
int n,m,size,top;
int uu[MAX],vv[MAX],ww[MAX],anc[MAX];
int up[MAX][],down[MAX][],maxw[MAX][],minw[MAX][],deep[MAX];
int head[MAX],head2[MAX],bin[MAX],stack[MAX],mp[MAX][],father[MAX];
bool mark[MAX]; struct Edge{
int v,id,next;
Edge(){}
Edge(int V,int ID,int NEXT):v(V),id(ID),next(NEXT){}
}edge[MAX*],edge2[MAX*]; void Init(int num){
for(int i=;i<=num;++i)head[i]=head2[i]=-,mark[i]=false;
size=top=;
}
void InsertEdge(int u,int v,int id){
edge[size]=Edge(v,id,head[u]);
head[u]=size++;
}
void InsertEdge2(int u,int v,int id){
edge2[size]=Edge(v,id,head2[u]);
head2[u]=size++;
}
void dfs(int u,int father,int k){
deep[u]=k;
for(int i=head[u];i != -;i=edge[i].next){
int v=edge[i].v;
if(v == father)continue;
dfs(v,u,k+);
}
}
void RMQ(int u,int father){
stack[++top]=u;
int fa=stack[top-];
up[u][]=down[u][]=;
maxw[u][]=minw[u][]=ww[u];
for(int i=;bin[i]<=top;++i){//2^i<=top
fa=stack[top-bin[i-]];
up[u][i]=max(max(up[u][i-],up[fa][i-]),maxw[fa][i-]-minw[u][i-]);
down[u][i]=max(max(down[u][i-],down[fa][i-]),maxw[u][i-]-minw[fa][i-]);
maxw[u][i]=max(maxw[u][i-],maxw[fa][i-]);
minw[u][i]=min(minw[u][i-],minw[fa][i-]);
mp[u][i]=stack[top-bin[i]];
}
for(int i=head[u];i != -;i=edge[i].next){
int v=edge[i].v;
if(v == father)continue;
RMQ(v,u);
}
--top;
}
int findset(int v){
if(v != father[v])father[v]=findset(father[v]);
return father[v];
}
void LCA(int u){
mark[u]=true;
father[u]=u;
for(int i=head2[u];i != -;i=edge2[i].next){
int v=edge2[i].v,id=edge2[i].id;
if(!mark[v])continue;
anc[id]=findset(v);
}
for(int i=head[u];i != -;i=edge[i].next){
int v=edge[i].v;
if(mark[v])continue;
LCA(v);
father[v]=u;
}
}
int search(int x){
int i=;
while(bin[i+]<=x)++i;
return i;
}
int Minw(int u,int anc){
int i=search(deep[u]-deep[anc]+);
if(bin[i] == deep[u]-deep[anc]+)return minw[u][i];
return min(minw[u][i],Minw(mp[u][i],anc));
}
int Maxw(int u,int anc){
int i=search(deep[u]-deep[anc]+);
if(bin[i] == deep[u]-deep[anc]+)return maxw[u][i];
return max(maxw[u][i],Maxw(mp[u][i],anc));
}
int Down(int u,int anc){
int i=search(deep[u]-deep[anc]+);
if(bin[i] == deep[u]-deep[anc]+)return down[u][i];
int downfa=Down(mp[u][i],anc);
downfa=max(downfa,down[u][i]);
int minwfa=Minw(mp[u][i],anc);
return max(downfa,maxw[u][i]-minwfa);
}
int UP(int u,int anc){
int i=search(deep[u]-deep[anc]+);
if(bin[i] == deep[u]-deep[anc]+)return up[u][i];
int upfa=UP(mp[u][i],anc);
upfa=max(upfa,up[u][i]);
int maxwfa=Maxw(mp[u][i],anc);
return max(upfa,maxwfa-minw[u][i]);
}
int main(){
bin[]=;
for(int i=;bin[i-]<MAX;++i)bin[i]=bin[i-]*;
int u,v;
while(~scanf("%d",&n)){
Init(n);
for(int i=;i<=n;++i)scanf("%d",ww+i);
for(int i=;i<n;++i){
scanf("%d%d",&u,&v);
InsertEdge(u,v,i);
InsertEdge(v,u,i);
}
size=;
scanf("%d",&m);
for(int i=;i<m;++i){
scanf("%d%d",uu+i,vv+i);
InsertEdge2(uu[i],vv[i],i);
InsertEdge2(vv[i],uu[i],i);
}
dfs(,-,);
RMQ(,-);
LCA();
for(int i=;i<m;++i){
int upmax=UP(uu[i],anc[i]),downmax=Down(vv[i],anc[i]);
int Minww=Minw(uu[i],anc[i]),Maxww=Maxw(vv[i],anc[i]);
printf("%d\n",max(max(upmax,downmax),Maxww-Minww));
}
}
return ;
}
/*
7
300
11
11
21
10
31
222
1 2
2 3
3 4
4 5
2 6
1 7
1
5 6
*/

poj3728之离线LCA+dp思想/RMQ+LCA(非常好的题目)的更多相关文章

  1. 【算法】RMQ LCA 讲课杂记

    4月4日,应学弟要求去了次学校给小同学们讲了一堂课,其实讲的挺内容挺杂的,但是目的是引出LCA算法. 现在整理一下当天讲课的主要内容: 开始并没有直接引出LCA问题,而是讲了RMQ(Range Min ...

  2. How far away ? HDU - 2586 【LCA】【RMQ】【java】

    题目大意:求树上任意两点距离. 思路: dis[i]表示i到根的距离(手动选根),则u.v的距离=dis[u]+dis[v]-2*dis[lca(u,v)]. lca:u~v的dfs序列区间里,深度最 ...

  3. LCA转换成RMQ

    LCA(Lowest Common Ancestor 最近公共祖先)定义如下:在一棵树中两个节点的LCA为这两个节点所有的公共祖先中深度最大的节点. 比如这棵树 结点5和6的LCA是2,12和7的LC ...

  4. poj 1330(RMQ&LCA入门题)

    传送门:Problem 1330 https://www.cnblogs.com/violet-acmer/p/9686774.html 参考资料: http://dongxicheng.org/st ...

  5. POJ 3728 The merchant(LCA+DP)

    The merchant Time Limit : 6000/3000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total ...

  6. hdu5293 lca+dp+树状数组+时间戳

    题意是给了 n 个点的树,会有m条链条 链接两个点,计算出他们没有公共点的最大价值,  公共点时这样计算的只要在他们 lca 这条链上有公共点的就说明他们相交 dp[i]为这个点包含的子树所能得到的最 ...

  7. HDU 6065 RXD, tree and sequence (LCA DP)

    RXD, tree and sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java ...

  8. 到底什么是dp思想(内含大量经典例题,附带详细解析)

    期末了,通过写博客的方式复习一下dp,把自己理解的dp思想通过样例全部说出来 说说我所理解的dp思想 dp一般用于解决多阶段决策问题,即每个阶段都要做一个决策,全部的决策是一个决策序列,要你求一个 最 ...

  9. hdu 3030 Increasing Speed Limits (离散化+树状数组+DP思想)

    Increasing Speed Limits Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

随机推荐

  1. struct-config.xml配置文件的解析

    //定义了xml文件的版本和编码<?xml version="1.0" encoding="UTF-8"?>//配置文件中的元素必须按照下述doc指 ...

  2. html乱码原因与网页乱码解决方法

    造成html网页乱码原因主要是html源代码内中文字内容与html编码不同造成.但无论是哪种情况造成乱码在网页开始时候都需要设置网页编码. charset编码设置 html网页乱码效果截图 一.乱码造 ...

  3. WEB-INF与Webroot

    WEB-INF:放在WEB-INF下的资源是浏览器访问不到的,但后台程序能跳转到的,但重定向不行

  4. solr注意事项-solrconfig中的默认搜索域会覆盖schema中的默认搜索域,注意copyfeild中被corp的字段搜索

    结论一:solrconfig.xml的默认搜索配置权限高于schema.xml中的默认搜索配置! 配置1:solrconfig.xml文件中关于select的配置: <requestHandle ...

  5. 框架之Struts2

    相比较hibernate简单了许多 案例:使用Struts2框架完成登录功能 需求分析 1. 使用Struts2完成登录的功能 技术分析之Struts2框架的概述 1. 什么是Struts2的框架 * ...

  6. bzoj2134 错选单位

    传送门 题目 Input n很大,为了避免读入耗时太多, 输入文件只有5个整数参数n, A, B, C, a1, 由上交的程序产生数列a. 下面给出pascal/C/C++的读入语句和产生序列的语句( ...

  7. Luogu 3292 [SCOI2016]幸运数字

    BZOJ 4568. 感觉很板. 前置技能:线性基.      放一篇感觉讲的比较丰富的博客: 戳这里. 首先要求在一个序列中任意选点使得异或和最大,当然是想到线性基了. 把问题转换到树上,如果每次询 ...

  8. Entity Framework Tutorial Basics(6):Model Browser

    Model Browser: We have created our first Entity Data Model for School database in the previous secti ...

  9. POJ 3411 Paid Roads (状态压缩+BFS)

    题意:有n座城市和m(1<=n,m<=10)条路.现在要从城市1到城市n.有些路是要收费的,从a城市到b城市,如果之前到过c城市,那么只要付P的钱, 如果没有去过就付R的钱.求的是最少要花 ...

  10. Java NIO学习笔记

    Java NIO学习笔记 一 基本概念 IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. 所有语言运行时系统提供执 ...