zoj 3649 lca与倍增dp
参考:http://www.xuebuyuan.com/609502.html
先说题意:
给出一幅图,求最大生成树,并在这棵树上进行查询操作:给出两个结点编号x和y,求从x到y的路径上,由每个结点的权值构成的序列中的极差大小——要求,被减数要在减数的后面,即形成序列{a1,a2…aj …ak…an},求ak-aj (k>=j)的最大值。
求路径,显然用到lca。
太孤陋寡闻,才知道原来倍增dp能用来求LCA。
用p[u][i]表示结点u的第1<< i 个祖先结点,则有递推如下:
for(int i=0;i<POW;i++) p[u][i]=p[p[u][i-1]][i-1]。
在对图dfs的时候即完成递推。
要想求两个结点的lca,首先使得两结点高度相同,若二者的父亲结点不同,则一直向上查找。dep数组表示结点的深度。
int LCA(int a,int b){
if(dep[a]>dep[b]) swap(a,b);
if(dep[a]<dep[b]){
//这一部分使得dep[a]==dep[b]
int tmp=dep[b]-dep[a];
for(int i=0;i<POW;i++) if(tmp&(1<<i))
//这里从POW-1到0来遍历也是一样的
b=p[b][i];
}
if(a!=b){
for(int i=POW-1;i>=0;i--) if(p[a][i]!=p[b][i])
a=p[a][i],b=p[b][i];
a=p[a][0],b=p[b][0];
}
return a;
}
如此即返回结点的lca。
用倍增遍历的思路:
因为一段路被二进制分成了一截一截,或者说路径长度被用二进制表示了出来。而两个结点的深度差即为“路径长度”,所以只要tmp&(1<<i),则表示这是“路径”的其中一个结点,以此类推,从而得到两个深度相同的结点。
有了这个基础之后,用相同的方式构建——
mx数组,mx[u][i]表示从u到其第1<<i个祖先结点路径上的最大值
mn数组,mn[u][i]表示从u到其第1<<i个祖先结点路径上的最小值
dp数组,dp[u][i],表示从u到其第1<<i个祖先结点路径上的最大差值
dp2数组,dp2[u][i],表示从其第1<<i个祖先结点到u路径上的最大差值
构建好后是查询部分。给出结点x和y,获得lca。
则路径被分成两段—— x->lca->y。则有三种可能性:
x到lca上的最大差值;lca到y上的最大差值;x到y上的最大差值(即lca到y的最大值减去x到lca的最小值)。比较一下即可。
这题真心涨姿势。代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=3e4+,M=N<<,POW=,inf=21e8;
int mx[N][POW],mn[N][POW],p[N][POW],dp[N][POW],dp2[N][POW];
int head[N],nxt[M],to[M],cnt,val[N],vis[N],dep[N];
int n,m,q,fa[N];
struct Edge{
int u,v,w;
bool operator < (const Edge e) const{
return w>e.w;
}
}E[M];
void ini(int n){
memset(head,-,sizeof(head));
cnt=;
memset(vis,,sizeof(vis));
fill(p[],p[n+],);
fill(mx[],mx[n+],-inf);
fill(mn[],mn[n+],inf);
fill(dp[],dp[n+],-inf);
fill(dp2[],dp2[n+],-inf);
dep[]=;
}
int find_(int x){
return x==fa[x]?x:fa[x]=find_(fa[x]);
}
void addedge(int u,int v){
to[cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt++;
}
int Kruskal(){
for(int i=;i<=n;i++) fa[i]=i;
sort(E,E+m);
int sum=;
for(int i=;i<m;i++){
int a=find_(E[i].u),b=find_(E[i].v);
if(a!=b){
fa[a]=b;
addedge(E[i].u,E[i].v);
addedge(E[i].v,E[i].u);
sum+=E[i].w;
}
}
return sum;
}
void dfs(int u,int f){
dep[u]=dep[f]+;
vis[u]=;
for(int i=head[u];~i;i=nxt[i]) if(!vis[to[i]]){
int v=to[i];
p[v][]=u;
mx[v][]=max(val[u],val[v]);
mn[v][]=min(val[u],val[v]);
dp[v][]=val[u]-val[v];
dp2[v][]=val[v]-val[u];
for(int j=;j<POW;j++){
p[v][j]=p[p[v][j-]][j-];
mx[v][j]=max(mx[v][j-],mx[p[v][j-]][j-]);
mn[v][j]=min(mn[v][j-],mn[p[v][j-]][j-]); dp[v][j]=max(dp[v][j-],dp[p[v][j-]][j-]);
dp[v][j]=max(dp[v][j],mx[p[v][j-]][j-]-mn[v][j-]); dp2[v][j]=max(dp2[v][j-],dp2[p[v][j-]][j-]);
dp2[v][j]=max(dp2[v][j],mx[v][j-]-mn[p[v][j-]][j-]);
}
dfs(v,u);
}
}
int LCA(int a,int b){
//第一次看到这样的LCA,holy high
//有点不明觉厉
if(dep[a]>dep[b]) swap(a,b);
if(dep[a]<dep[b]){
//这一部分使得dep[a]==dep[b]
int tmp=dep[b]-dep[a];
for(int i=POW-;i>=;i--) if(tmp&(<<i))
b=p[b][i];
}
if(a!=b){
//如果高度相等,而a!=b
for(int i=POW-;i>=;i--) if(p[a][i]!=p[b][i])
a=p[a][i],b=p[b][i];
a=p[a][],b=p[b][];
}
return a;
}
int getmax(int x,int lca){
int ans=,tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=max(ans,mx[x][i]);
x=p[x][i];
}
return ans;
}
int getmin(int x,int lca){
int ans=inf,tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=min(ans,mn[x][i]);
x=p[x][i];
}
return ans;
}
int getleft(int x,int lca){
int ans=,minn=inf;
int tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=max(ans,dp[x][i]);
ans=max(ans,mx[x][i]-minn);
minn=min(minn,mn[x][i]);
x=p[x][i];
}
return ans;
}
int getright(int x,int lca){
int ans=,maxx=;
int tmp=dep[x]-dep[lca];
for(int i=POW-;i>=;i--) if(tmp&(<<i)){
ans=max(ans,dp2[x][i]);
ans=max(ans,maxx-mn[x][i]);
maxx=max(maxx,mx[x][i]);
x=p[x][i];
}
return ans;
}
int main(){
freopen("in.txt","r",stdin);
while(~scanf("%d",&n)){
for(int i=;i<=n;i++)
scanf("%d",&val[i]);
ini(n);
scanf("%d",&m);
for(int i=;i<m;i++)
scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
printf("%d\n",Kruskal());
dfs(,);
scanf("%d",&q);
int x,y;
while(q--){
scanf("%d%d",&x,&y);
int lca=LCA(x,y);
int ans=getmax(y,lca)-getmin(x,lca);
ans=max(ans,getleft(x,lca));
ans=max(ans,getright(y,lca));
printf("%d\n",ans);
}
}
return ;
}
zoj 3649 lca与倍增dp的更多相关文章
- POJ3728The merchant (倍增)(LCA)(DP)(经典)(||并查集压缩路径?)
There are N cities in a country, and there is one and only one simple path between each pair of citi ...
- Social Net ZOJ - 3649
Social Net ZOJ - 3649 题意: 反正原题题意我是看不懂... 参考:http://www.cnblogs.com/names-yc/p/4922867.html 给出一幅图,求最大 ...
- Codeforces 1140G Double Tree 倍增 + dp
刚开始, 我以为两个点肯定是通过树上最短路径过去的, 无非是在两棵树之间来回切换, 这个可以用倍增 + dp 去维护它. 但是后来又发现, 它可以不通过树上最短路径过去, 我们考虑这样一种情况, 起点 ...
- P5024 保卫王国[倍增+dp]
窝当然不会ddp啦,要写这题当然是考虑优化裸dp啦,但是这题非常麻烦,于是变成了黑题. 首先,这个是没有上司的舞会模型,求图的带权最大独立集. 不考虑国王的限制条件,有 \[ dp[x][0]+=dp ...
- 关于LCA的倍增解法的笔记
emmmmm近日刚刚学习了LCA的倍增做法,写一篇BLOG来加强一下印象w 首先 何为LCA? LCA“光辉”是印度斯坦航空公司(HAL)为满足印度空军需要研制的单座单发轻型全天候超音速战斗攻击机,主 ...
- LCA的倍增算法
LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链 ...
- [模板]LCA的倍增求法解析
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 洛谷 P1613 跑路 (倍增 + DP + 最短路)
题目链接:P1613 跑路 题意 给定包含 \(n\) 个点和 \(m\) 条边的有向图,每条边的长度为 \(1\) 千米.每秒钟可以跑 \(2^k\) 千米,问从点 \(1\) 到点 \(n\) 最 ...
- ZOJ - 3649 树上倍增
题意:给出一个图,先求出最大生成树,然后多次询问树上路径\(u→v\)的有向最大极差\(max(a_i-a_j),i>j\),其中\(i\)和\(j\)指代节点在路径中出现的顺序 极差具有单调性 ...
随机推荐
- [机房合作]—SqlHelper我们又约了
一.是什么? SqlHelper是一个基于·NET Framework的数据库操作组件,组件中包括数据库操作方法. 二.为什么? 为什么要用SqlHelper类? 1.SqlHelper用 ...
- vi和vim上查找字符串
方法/步骤 1 我们以samba的配置文件为例,搜索一个user的字符串. vim /etc/samba/smb.conf 打开smb.conf 2 命令模式下,输入/user "/&quo ...
- [Rust] Setup Rust for WebAssembly
In order to setup a project we need to install the nightly build of Rust and add the WebAssembly tar ...
- vue 获取当前时间 格式YYYY-MM-DD
函数封装: /** * 获取当前时间 * 格式YYYY-MM-DD */ Vue.prototype.getNowFormatDate = function() { var date = new Da ...
- ZOJ 2859 二维线段树
思路:自己写的第二发二维线段树1A.哈哈,看来对二维的push操作比較了解了:可是还没遇到在两个线段树中同一时候进行push操作的,事实上这题我是想在x维和y维同一时候进行push操作的.可是想了好久 ...
- Cocos2d-x 3.2 Lua演示样例CurrentLanguageTest(当前语言环境)
Cocos2d-x 3.2 Lua演示样例CurrentLanguageTest(当前语言环境) 转载请注明:IT_xiao小巫 本篇博客介绍Cocos2d-x 3.2给我们提供的一个样例.获取当前程 ...
- SE11 数据表中 日志数据更改 勾选的作用
[园工]HF-abap-Rainy(574570549) 11:10:12这个有啥作用,勾上了怎么查修改日志呢,[园丁]SH-CRM-ALEX(8738890) 11:13:53SCU3[ ...
- IntelliJ Idea 工具
IntelliJ Idea 优化: 1.如何取消文件自动保存 File->Settings -> Appearance&Behavior -> System Setting ...
- (MySQL里的数据)通过Sqoop Import HDFS 里 和 通过Sqoop Export HDFS 里的数据到(MySQL)(五)
下面我们结合 HDFS,介绍 Sqoop 从关系型数据库的导入和导出 一.MySQL里的数据通过Sqoop import HDFS 它的功能是将数据从关系型数据库导入 HDFS 中,其流程图如下所示. ...
- git不同分支局部代码合并 git cherry-pick
cherry-pick 可以局部代码合并. cherry-pick不仅可以用在不同分支之间,还可以用在同一个分支上. 比如说你在某一个向某个分支中添加了一个功能,后来处于某种原因把它给删除了,然而后来 ...