poj 3728 The merchant// lca(倍增实现) + dp

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 6437   Accepted: 2251

Description

There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and wants to earn as much money as possible in each path. When he move along a path, he can choose one city to buy some goods and sell them in a city after it. The goods in all cities are the same but the prices are different. Now your task is to calculate the maximum possible profit on each path.

Input

The first line contains N, the number of cities.
Each of the next N lines contains wi the goods' price in each city.
Each of the next N-1 lines contains labels of two cities, describing a road between the two cities.
The next line contains Q, the number of paths.
Each of the next Q lines contains labels of two cities, describing a path. The cities are numbered from 1 to N.

1 ≤ N, wi, Q ≤ 50000

Output

The output contains Q lines, each contains the maximum profit of the corresponding path. If no positive profit can be earned, output 0 instead.

Sample Input

4
1
5
3
2
1 3
3 2
3 4
9
1 2
1 3
1 4
2 3
2 1
2 4
3 1
3 2
3 4

Sample Output

4
2
2
0
0
0
0
2
0

题意:给出一个树,结点有一个w[i],给出q个询问,每个询问给出u和v,在u->v的路径中选出两个点a,b(a,b可以一样,a比b先出现),求出最大的w[b]-w[a]。

对于一个询问u,v,ans=max(u到lca(u,v)之间的最大值,lca(u,v)到v之间的最大值,根节点到v之间的最大值-根节点到u之间的最小值)。

利用倍增思想,处理出fa[v][k](v号结点上升2^k所到的结点),mx[v][k],mi[v][k](v号结点上升2^k所到结点x,x,v之间的最大值及最小值),up[v][k](v号结点上升2^k所到结点x,v和x之间能赚到钱的最大值)down[v][k](从距离v  2^k步所在的结点x下降到v,x和v之间能赚到钱的最大值)。

具体dp转移的过程看注释。这题还是挺有质量的。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<climits>
using namespace std;
const int max_n=5e4+5,max_logn=24;
struct no{int to,ne;};
no e[max_n*2];int head[max_n],edgenum;
void initvector(){edgenum=0;memset(head,-1,sizeof(head));}
void addedge(int from,int to){//头插法no E={to,head[from]};e[edgenum]=E;head[from]=edgenum++;
}int fa[max_n][max_logn],de[max_n],root=1;
int n,w[max_n];
int mx[max_n][max_logn],mi[max_n][max_logn];
int up[max_n][max_logn],down[max_n][max_logn];void dfs(int v,int p,int d){//所有都是向上走2^k步 所代表的含义fa[v][0]=p;de[v]=d;mx[v][0]=max(w[v],w[p]);mi[v][0]=min(w[v],w[p]);//只走2^0次步 预处理up[v][0]=max(w[p]-w[v],0);down[v][0]=max(w[v]-w[p],0);for(int i=head[v];i!=-1;i=e[i].ne){if(e[i].to!=p)dfs(e[i].to,v,d+1);}
}
void init(int V){//预处理fa,dp的数组dfs(root,-1,0);for(int k=0;k+1<max_logn;k++){for(int v=1;v<=V;v++){int tfa=fa[v][k];if(tfa<0) fa[v][k+1]=-1;else {//可达fa[v][k+1]=fa[tfa][k];mx[v][k+1]=max(mx[v][k],mx[tfa][k]);mi[v][k+1]=min(mi[v][k],mi[tfa][k]);up[v][k+1]=max(up[v][k],up[tfa][k]);up[v][k+1]=max(up[v][k+1],mx[tfa][k]-mi[v][k]);//跨两个小区间down[v][k+1]=max(down[v][k],down[tfa][k]);down[v][k+1]=max(down[v][k+1],mx[v][k]-mi[tfa][k]);//和up相反}}}
}
int find_lca(int u,int v){if(de[u]>de[v]) swap(u,v);for(int k=0;k<max_logn;k++){if((de[v]-de[u])>>k&1) v=fa[v][k];}if(u==v) return u;for(int k=max_logn-1;k>=0;k--){if(fa[u][k]!=fa[v][k]){u=fa[u][k],v=fa[v][k];}}return fa[u][0];
}
int find_up(int u,int lca,int &remin){remin=INT_MAX/2;int maxup=0,pre_min=INT_MAX/2;//维护前缀最小值for(int k=max_logn-1;k>=0;k--){if((de[u]-de[lca])>>k&1){remin=min(remin,mi[u][k]);maxup=max(maxup,up[u][k]);maxup=max(maxup,mx[u][k]-pre_min);//跨小区间跟新pre_min=min(pre_min,mi[u][k]);u=fa[u][k];}}return maxup;
}
int find_down(int v,int lca,int &remax){remax=INT_MIN/2;int maxdown=0,pre_max=INT_MIN/2;for(int k=max_logn-1;k>=0;k--){if((de[v]-de[lca])>>k&1){remax=max(remax,mx[v][k]);maxdown=max(maxdown,down[v][k]);maxdown=max(maxdown,pre_max-mi[v][k]);pre_max=max(pre_max,mx[v][k]);v=fa[v][k];}}return maxdown;
}
int find_ans(int u,int v){int lca=find_lca(u,v);int re=0;int up_min_val=INT_MAX/2,down_max_val=INT_MIN/2;re=max(re,find_up(u,lca,up_min_val));//u-lcare=max(re,find_down(v,lca,down_max_val));//lca-vre=max(re,(down_max_val-up_min_val));//包含根节点return re;
}
int main(){initvector();scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&w[i]);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);addedge(u,v),addedge(v,u);}init(n);int q;scanf("%d",&q);while(q--){int xx,yy;scanf("%d%d",&xx,&yy);printf("%d\n",find_ans(xx,yy));}return 0;
}

4.24更:

终于肝出来了并查集路径下dp+离线tarjanlca的解法

照样维护up,down,mi,mx,不过都是当前状态下的。

#include<vector>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int max_n= 5e4+5;
struct qno{int to,id;};
vector<qno>q[max_n];//询问
int ans[max_n];
vector<int>g[max_n];//树
int w[max_n],uu[max_n],vv[max_n];int n,Q;//uu:询问的起点,vv:询问的终点
int fa[max_n],vis[max_n];
int up[max_n],down[max_n],mx[max_n],mi[max_n];//都是在当前状态下,到父节点的关系
struct lcano{int x,id;};//lca下的询问
vector<lcano>qq[max_n];
int found(int x){//并查集路径下dpif(fa[x]==x)return x;int t=fa[x];fa[x]=found(fa[x]);up[x]=max(up[t],up[x]);up[x]=max(up[x],mx[t]-mi[x]);down[x]=max(down[t],down[x]);down[x]=max(down[x],mx[x]-mi[t]);mx[x]=max(mx[t],mx[x]);mi[x]=min(mi[t],mi[x]);return fa[x];
}void tarjan(int u){vis[u]=true;for(int i=0;i<q[u].size();i++){int qid=q[u][i].id,to=q[u][i].to; //lca为found(to)if(vis[to]){int lca=found(to);qq[lca].push_back(lcano{to,qid});//先存起来,只有lca以下的节点都访问过了才可以计算}}for(int i=0;i<g[u].size();i++){int to=g[u][i];if(!vis[to]){tarjan(to);fa[to]=u; }}for(int i=0;i<qq[u].size();i++){//u子树都访问过了,那么u做为询问的lca,可以执行lca是u的询问,回溯的遍历顺序保证正确可行性int id=qq[u][i].id;found(uu[id]),found(vv[id]);//左边更新,右边跟新ans[id]=max(up[uu[id]],down[vv[id]]);ans[id]=max(ans[id],mx[vv[id]]-mi[uu[id]]);}}
int main(){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&w[i]);for(int u=1;u<=n;u++){fa[u]=u;up[u]=0;down[u]=0;mx[u]=w[u];mi[u]=w[u];}for(int i=1;i<n;i++){int scu,scv;scanf("%d%d",&scu,&scv);g[scu].push_back(scv);g[scv].push_back(scu);}scanf("%d",&Q);for(int i=1;i<=Q;i++){scanf("%d%d",&uu[i],&vv[i]);q[uu[i]].push_back(qno{vv[i],i});q[vv[i]].push_back(qno{uu[i],i});}tarjan(1);for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);return 0;
}
/*6
5 3 1 4 2 7
1 2
1 3
2 4
2 5
3 6
2
2 4
4 2*/

poj 3728 The merchant// lca(倍增实现) + dp || tarjan+并查集路径上dp相关推荐

  1. [拓扑排序][DP][Tarjan][并查集]JZOJ 4253 QYQ在艾泽拉斯

    Description 在艾泽拉斯的无尽之海里,有着一群不为人知的由各个种族的冒险者统治的岛屿,这些岛屿都很庞大,足以在上面建造许多的城市,城市之间有一些单向道路连接. 有一天,QYQ无意中发现了这些 ...

  2. Rochambeau POJ - 2912 (枚举和加权并查集+路径压缩)找唯一裁判

    题意:有n个人玩石头剪刀布,有且只有一个裁判.除了裁判每个人的出拳形式都是一样的. a<b表示b打败a,a=b表示a和b出拳一样,平手.a>b表示a打败b. 给出m个回合的游戏结果,问能否 ...

  3. 【POJ - 3694】Network(对dfn求lca 或 缩点+lca 或 边双连通+并查集)

    题干: 网络管理员管理大型网络.该网络由N台计算机和成对计算机之间的M链路组成.任何一对计算机都通过连续的链接直接或间接连接,因此可以在任何两台计算机之间转换数据.管理员发现某些链接对网络至关重要,因 ...

  4. 洛谷P7518:宝石(倍增、可撤销并查集)

    解析 算法一 定义 upx,kup_{x,k}upx,k​ 为节点 xxx 从自己的颜色所在位置在返祖链上往后跳 2k2^k2k 个颜色到达的节点. 可以像倍增一样的求解. 这样对于一次询问 (s,t ...

  5. 【POJ】1308 Is It A Tree?((并查集 + set)or (map))

    http://poj.org/problem?id=1308 这个题数组开到200就可以了,但题目中貌似没有说呢? 读入每一对顶点,看看他们是否在同一个集合中,如果是的话,肯定成环,不是一棵树. 用s ...

  6. 路径空间HDOJ 4514 - 湫湫系列故事——设计风景线 并查集+树型DP

    最近研究路径空间,稍微总结一下,以后继续补充: 题意有没说楚清的...两点间最多一条路径.... 先用并查集检查无向图否是有环... 若干个无环的无向图就是一丛林了... 那么目题转化为在一棵树上找最 ...

  7. HDU5575 Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)

    题目大意: 有一个1维的长度为N,高度无限的水柜,现在要用N-1个挡板将其分为N个长度为1的小格,然后向水柜中注水,水可以低于挡板也可以以溢出去(这样就要与旁边格子的水位相同),现在有M次探测,探测i ...

  8. poj 1470(简单LCA 倍增法)

    题意:给你一个树,有若干个询问,然后让你统计每个结点在询问中做了几次LCA.按照结点顺序输出. 思路:这也是简单的LCA题目,我用的是倍增法.每次查询在相应结点标记上++,最后输出即可.这道题的输入处 ...

  9. poj 2513 Colored Sticks( 字典树哈希+ 欧拉回路 + 并查集)

    题目:http://poj.org/problem?id=2513 参考博客:http://blog.csdn.net/lyy289065406/article/details/6647445 htt ...

最新文章

  1. 华为(苏州)人工智能创新中心正式揭牌
  2. Scala连接mongodb数据库
  3. 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一1.15 如何掌握拍摄方向
  4. DM 源码阅读系列文章(四)dump/load 全量同步的实现
  5. Nginx学习笔记(二) Nginx--connectionrequest
  6. python数据分析之(1)数据输入和输出
  7. 黑盒测试的测试方法及其案例
  8. window10 彻底关闭自动更新
  9. ueditor统计字数中文_UEditor编辑器 字符数统计和字符数限制 问题
  10. springcloud五大神兽之Gateway
  11. 2003年我收集的一些知名blog
  12. FuzzFactory: Domain-Specific Fuzzing with Waypoints
  13. 多Excel文件内容查询工具。
  14. ASEMI超快恢复二极管与肖特基二极管可以互换吗
  15. 使用Python语言实现Bmi指数计算器
  16. 数一独有:多元函数积分学中的基本公式及其应用
  17. broadcom 802.11n linux驱动下载,broadcom 802.11n驱动下载
  18. 【半监督医学图像分割 2021 CVPR】CVRL 论文翻译
  19. java获取kdc的tgt_Windows 服务器 2008年密钥分发中心 (KDC) 拒绝 TGS 请求 TGT 更新后...
  20. virtuoso从电路图导入版图_基于Virtuoso平台的单片射频收发系统PCB电路仿真与版图设计...

热门文章

  1. VK1623,DICE(邦定COB)/COG(绑定玻璃用)段码LCD液晶显示驱动芯片,支持最大48EGx8COM
  2. 被深信服上网行为管理器AC拒绝的操作如何正常访问
  3. 小明加密通道进入_门禁系统跟闸机通道的区分是什么?功能是一样吗
  4. 《牛客刷verilog》Part I Verilog快速入门
  5. ogm 算法_如何在Windows Vista中播放.OGM视频文件
  6. 人生最大的危机就是没有危机感
  7. html 在 ul 加分隔线,的Html边界分隔在UL-L1之间的标题标记
  8. C++以及java学习方法和路线
  9. 【题解】文体(划掉)陌上花开
  10. 格网DEM生成不规则三角网TIN